Knox for Craft CMS

Troubleshooting

Start at the log

Knox → Log records every call with its status, timing and Fortnox's own numeric error code, which is far more useful than the HTTP status. On Pro it keeps the request and response bodies too.

php craft knox/log/last-error     # exits non-zero if anything is wrong

That exit code makes it usable from monitoring.

Fortnox error codes

CodeMeansDo
2000310The token is missing or wrongReconnect. If it recurs immediately, the Client Secret is wrong.
2000663No access to that scopeThe scope was not granted at approval time. Reconnect — changing the setting is not enough.
2001103The account has no API licenceA Fortnox subscription question, not a Knox one. Contact Fortnox.
2000423Account not foundAn account in your mapping is not in the chart. Press Check these exist in Fortnox.
2003275Not authorisedUsually the same as 2000663.

"Knox is not connected to Fortnox"

Either it never was, or the refresh token expired.

Fortnox invalidates a refresh token 45 days after it is issued, and the clock restarts only when it is used. A shop that takes no orders for seven weeks — or a staging site nobody orders on — comes back to a dead connection with nothing wrong.

php craft knox/connect/status

If it says expired, press Connect to Fortnox again. To stop it happening, put knox/connect/refresh on a weekly cron.

"This connection does not hold the … scopes"

You added a scope to Knox's settings after connecting. Fortnox froze the scope set when you approved the integration, so the new one is not granted and never will be until you reconnect.

This is not Knox being cautious — a call needing an ungranted scope comes back 403 with a code that does not obviously say "scope".

An invoice is Blocked

Nothing was sent. The reason is on the row, and it is one of a short list:

"…is taxed at 8.5%, which is not one of the VAT percentages a Fortnox invoice row can carry" — a Fortnox row takes a whole percentage from your configured rates. Fix the tax rate in Commerce, or this order cannot be invoiced through Fortnox at all.

"…carries 2 different VAT rates" — a Fortnox row has exactly one. Split the line item.

"The order has VAT both included in its prices and added on top"VATIncluded is invoice-level in Fortnox. Fix the tax rates so the order is consistent, or pin VAT in prices in the settings.

"This order needs the Fortnox VAT type EUREVERSEDVAT, which lives on the customer record" — turn on Sync customers (Pro). See VAT.

"Fortnox needs a customer on every invoice, and Knox has none for this order" — set a collective customer number, or turn on customer syncing.

"The invoice would come to X but the order was charged Y" — the reconciliation guard. This is Knox refusing to send something wrong, and it means the model and the order genuinely disagree by more than rounding. Check the order's adjustments; a shipping row switched off while shipping was charged does exactly this.

An invoice Does not match the order

It exists in Fortnox, and its total is not what the customer paid. Both figures are on the detail screen.

If Fortnox öresutjämning is non-zero, that is the cause and the fix is in Fortnox, not in Knox — see Öresavrundning.

If it is zero, the difference is one Knox did not predict. Look at the rows on the invoice in Fortnox; something was changed there after Knox created it.

An invoice is Unknown

Fortnox never answered the create. It may or may not hold the invoice, so Knox will not send it again — that is the whole point of the state.

php craft knox/sync/reconcile

or press Check with Fortnox. Knox looks the invoice up by the order reference it stamps on every invoice, and then either claims what Fortnox holds or clears the way for a fresh attempt.

Never resolve this by hand-creating an invoice in Fortnox — the reconcile will not find it if the reference is missing, and you will end up with two.

Bookkeeping fails in January

Fortnox has no financial year covering 2027-01-04

Nobody has created the new financial year in Fortnox yet. Create it there, then press Bookkeep again — the button re-asks Fortnox rather than trusting the cached answer.

Rate limiting

Fortnox allows 25 requests per rolling five seconds per client ID and company. Knox paces itself across every queue worker on the site so they share one budget rather than each politely staying under the limit and collectively blowing it.

If you see 429s anyway, raise Minimum interval between calls above 220 ms. Something else is using the same integration credentials.

An invoice sits in Fortnox's "to print" pile

Turn on Mark as sent. Your shop already emailed the customer a receipt; without this flag the invoice waits to be printed forever.

Nothing happens at all

Check, in order:

  1. php craft knox/connect/status — is it connected?
  2. Is the trigger set to Only when asked?
  3. Is Only fully paid orders on, with an unpaid order?
  4. Is the queue running? Invoicing is always a queue job.
  5. Knox → Log — a call that failed is recorded even when nothing appears in the invoice list.

Getting a clean answer for a single order

php craft knox/sync/order 1234 --dry

Prints the order total, the invoice total, the VAT type, the reasoning, every notice, and the exact payload — without sending anything. It is the fastest way to see what Knox thinks about one order.