ZIFFER home

Support: who to write to, what we promise, and what every refusal means

For the admin who owns the integration.

For the admin who owns the integration. Written 2026-09-07 (ACP-298). Every refusal in the table below is derived from docs/onboarding/sdk.md section 5 and docs/onboarding/executor.md section 6 by tools/check-support-doc.py, which fails if a refusal is documented and has no row here, or if a row here names a refusal neither document publishes. If this file disagrees with either of those, they are right and this one is stale.


1. The two ways to reach us

AddressUse it forAnswered
Writehello@ziffer.ioeverything. Questions, refusals you cannot explain, a leg that looks slow, a document that is wrong.in the times in section 2
Chatthe chat button on ziffer.iothe same, when you want an answer while you are at the keyboard.in working hours

Chat and email reach the same people. A refusal is not an incident. A refusal is the system working; section 4 says what each one means and who moves next.

There is no customer status page yet, and no automatic notification when a leg of our deployment is degraded. Both are named as not-yet in section 6 rather than implied. Until they exist, ask.

2. Severity, and what each one buys you

Severity is set by what you can no longer do, never by how the request was written. We will move a ticket's severity up or down and say why in the ticket.

SeverityWhat qualifiesFirst responseUpdates until it closesPaged on our side
1No decision is being reached at all, or a control did not hold: an action ran that a receipt did not authorise, an audit chain gap, a replayed receipt that executed.1 hour, in working hourshourlyyes, immediately
2Decisions are reached but a path is unusable: a deferred release never releases, one door refuses everything, receipts arrive but cannot be delivered.4 working hoursevery 4 working hoursyes, in working hours
3A refusal you cannot explain, or behaviour that disagrees with a document. Nothing is down.1 working daydailyno
4A question, a documentation defect, a feature request.3 working dayson changeno

Working hours are 09:00 to 18:00 Paris time (Europe/Paris), Monday to Friday, except French public holidays.

What "paged on our side" is not. The alert classes in section 4 are raised to the audience your own signed bundle names in its alert_targets.json, one entry per class, and a class naming nobody is refused when the bundle is loaded. That audience is yours. Our being paged is a separate arrangement over our own deployment, and it is not a substitute for yours: if your alert_targets.json names an address nobody reads, nobody reads it.

By class, on our side:

Alert classOur severityWhy
AUDIT_INTEGRITY, LEDGER_REPLAY, ATTESTATION_INVALID1each is a control reporting that something it exists to prevent was attempted
SIGNING_SUBSTRATE, BUNDLE_INVALID1nothing can be signed or nothing can be loaded, so nothing is being decided
RECOMPUTATION_MISMATCH, CONTEXT_STORE, DEFERRED_RELEASE, ATTESTATION_QUEUE_DEPTH2one path is unusable and the others are not
SUITE_BELOW_FLOOR, RECEIPT_INVALID3in almost every case a floor or a build on your side, and the receipt was correctly refused

SIGNING_SUBSTRATE, BUNDLE_INVALID and ATTESTATION_QUEUE_DEPTH are three of the eleven classes your bundle must name an audience for. They are not in section 4's table because neither onboarding document publishes them as something you can be handed: they are raised inside our perimeter.

3. What to put in a report

Five things. With them a refusal is usually answered on the first reply; without them the first reply asks for them.

  1. Your tenant. The label, exactly as it appears in your bundle's manifest.
  2. The attestation id, if the action got as far as one.
  3. The receipt, base64 or as bytes, or the proposal if no receipt came back.
  4. The refusal name: the clause id or the alert class, spelled as section 4 spells it. This is the machine-readable half. The message beside it is for a human and is not part of the contract, so quote the id and not the sentence.
  5. When, in UTC, and what you were doing.

Never send a private key, a seed, or an API key. Nothing we ask for needs one, and a report is not a channel we treat as secret.

4. Every refusal, what it means, and what to do now

How to read "who fixes it". It names who owns the fix once the cause is known, not who reports it. you means the change is in your configuration, your build or your data. us means the change is in ours. you and us means the first move is yours and the fix is likely ours, or the cause genuinely sits across the boundary.

A refusal is not a network error, and none of these should be retried. Every one of them is deterministic on the same input: asking again gets the same answer one round trip later. A dependency that could not answer is a different thing entirely, and is not in this table: there the Executor reaches no verdict, reports nothing, and the work stays queued for the next poll.

refusaldocumented inwhat it meanswho fixes itwhat to do now
AB-0sdk.md section 5The bytes are not a version-3 receipt. Almost always the wrong value was passed to verify.youCheck what you handed verify. If it is exactly what our decision API returned, unchanged, report it with the bytes.
AB-6sdk.md section 5The signed body is larger than the cap. A receipt we issued should never be.usDo not retry. Report it with the receipt; it is ours.
AT-8asdk.md section 5The bytes are not UTF-8 JSON at all. Usually a transport or an encoding step between us and verify.youCompare the bytes on the wire with the bytes you pass. Look for a re-encoding, a truncation, or a logging step in between.
CR-1sdk.md section 5The receipt declares a signature suite this build does not know, declares none, or your ZIFFER_SUITE_FLOOR is not a suite this build knows. An unknown suite always fails closed.you and usCheck the spelling of ZIFFER_SUITE_FLOOR first, then your SDK version. If the SDK is current and the receipt names a suite it does not know, report it.
CR-4sdk.md section 5The receipt's suite does not contain every primitive your floor requires. The control worked: the receipt is weaker than you asked for.you and usConfirm the floor you set is the floor you meant. If it is, report it: a receipt below your floor is ours to explain.
9.3-1sdk.md section 5A signature primitive did not verify. The composition is conjunctive, so every primitive must pass and one did not.you and usStop. Do not retry and do not act on the receipt. Confirm you are verifying against the bundle you activated, then report it with the receipt.
9.3-2sdk.md section 5The decision value is not one this domain defines.usDo not retry. Report it with the receipt.
9.3-3sdk.md section 5The receipt is not bound to the proposal you passed. Usually two calls in flight and the wrong pair compared.youMatch each receipt to the proposal it answered before verifying. If they are the pair we returned together, report it.
9.3-5sdk.md section 5Your clock says the receipt has expired.youCheck the verifying host's clock against UTC. Clock drift is the common cause; a genuinely late receipt is the other.
L-14sdk.md section 5The receipt's validity window is longer than the specification permits, so it was refused before its expiry was consulted.usDo not retry. Report it with the receipt; the window is set on our side.
WE-4sdk.md section 5The receipt's nonce is not a well-formed 128-bit value.usDo not retry. Report it with the receipt; we mint the nonce.
L-17sdk.md section 5The nonce is the right shape but not the required length. Same cause as WE-4 and the same owner.usDo not retry. Report it with the receipt.
9.3-4sdk.md section 5The receipt's policy basis is not the bundle the Executor holds. Almost always the window right after a policy publish: readers pick up a new epoch on their own poll, so for up to two intervals — 30 seconds at the default 15 — one process can still be an epoch behind another. The receipt is refused rather than executed under rules the Executor cannot see.youThe exception to the "never retry a refusal" rule above. Retry the proposal once, 30 seconds later. If it persists after your publish workflow printed active, stop and report it with the receipt: outside that window it means an Executor that never picked up a bundle, or a receipt from another deployment.
LEDGER_REPLAYexecutor.md section 6A consumed identifier was claimed again, or an origin was rebound. Either work you already executed came back, or something replayed a receipt.you and usCheck first whether your Executor completed what it consumed: delivery is at-least-once and completing sloppily makes this alert routine. If your completions are clean, treat it as an incident and page.
RECOMPUTATION_MISMATCHexecutor.md section 6The risk or reversibility the receipt states is not what your signed bundle says it should be. The verifier recomputes both and does not take the receipt's word.usDo not act on the receipt. Report it with the receipt and your bundle's tree hash.
SUITE_BELOW_FLOORexecutor.md section 6The same condition as CR-4, reached by the Executor rather than by your own verify.you and usConfirm the floor in your bundle is the floor you meant, then report it.
CONTEXT_STOREexecutor.md section 6The live capability check at execution time disagrees with what was decided. The world moved between the decision and the action.youCheck whether the operator's capability changed after the proposal was made. If nothing changed on your side, report it.
AUDIT_INTEGRITYexecutor.md section 6The audit chain or one of its anchors did not hold.usWrite to us at once. Do not treat any receipt from the affected window as settled until we answer.
ATTESTATION_INVALIDexecutor.md section 6The approval quorum does not hold: too few valid attesters, a duplicate, or an attester the bundle does not name.you and usCheck your bundle's attester list and roles against who actually approved. If they agree, page.
HM-3executor.md section 6An approver's key kind and the approval's declared algorithm disagree: a person's entry answering for a machine's suite, or the other way round.usDo not retry. Report it with the receipt: neither side of that disagreement is yours to set.
HM-4executor.md section 6A human approval did not verify: the wrong site, no user verification, a challenge that answers something else, or a signature counter that did not advance. The last one means the credential has been copied or the approval was replayed.you and usAsk the approver to approve again from your own approval page. If it happens twice for one person, treat their authenticator as compromised and re-enrol it before doing anything else.
DEFERRED_RELEASEexecutor.md section 6Something in the hold, the notice, or an acknowledgement did not hold for an action that was waiting to be released.youCheck that your notice recipients are reachable and that acknowledgements are being sent. Then report it with the action id.
RECEIPT_INVALIDexecutor.md section 6Anything else the Executor refuses on the receipt's own bytes. The catch-all, so the clause id in the alert is the useful part.usReport it with the clause id from the alert, not just the class.
CL-2executor.md section 6The single-use claim failed: the ledger already holds this identifier, or it could not confirm the identifier is absent and the Executor failed closed.you and usIf the same receipt was delivered twice, that is expected and is not an anomaly. If it was delivered once, page: an unconfirmable ledger is our outage.
CL-3executor.md section 6A consumed identifier class was claimed twice: a receipt nonce, an attestation id, or an epoch mark. One receipt executes once.youConfirm your Executor completes every unit of work it consumes. Report it if it does and this still fires.
DS-6eexecutor.md section 6The re-drive bound for one action was reached. Re-drives are capped per action by your bundle, and the cap is there because an unbounded retry loop against a target that answers "indeterminate" is an amplification channel.youStop re-driving that action and find out what the target is actually doing. Raise the cap in your bundle only once you know.
DS-6fexecutor.md section 6A re-drive named an origin that is not the one the ledger pinned for that proposal, or something tried to rebind an existing proposal to a different origin.you and usDo not retry. This is a replay control firing; page.
TR-8executor.md section 6The risk level recomputed from your signed bundle is not the one the receipt states. The clause under RECOMPUTATION_MISMATCH for risk.usDo not act on the receipt. Report it with the receipt and your bundle's tree hash.
RV-3executor.md section 6The reversibility class recomputed from your signed bundle is not the one the receipt states. The clause under RECOMPUTATION_MISMATCH for reversibility.usDo not act on the receipt. Report it with the receipt and your bundle's tree hash.
9.3-9executor.md section 6The clause under CONTEXT_STORE: the capability check at execution time did not agree with the decision.youSame as CONTEXT_STORE. Check what changed in the operator's capabilities between the two moments.
AU-7executor.md section 6The audit record that must cover an action was not there, or was not covering, before the action was released. Ordering, not presence: the record comes first.usPage. This is the clause under AUDIT_INTEGRITY and it is ours.

5. Two things that look like refusals and are not

A dependency that could not answer. If the audit service, the Context Store or the ledger cannot be reached, no verdict is reached, nothing is reported, and the work stays queued. The next poll asks again. That is not in the table above because there is no refusal name to act on. If it persists past a few minutes, it is a severity 2.

The same receipt arriving twice. Delivery is at-least-once and execution is not. A poll marks nothing, so work comes back until you complete it. Being handed the same receipt twice is normal. Executing it twice is what CL-2 and LEDGER_REPLAY exist to stop.

6. What this does not give you yet

Stated rather than implied, because each is something an admin would reasonably assume exists.

  • No customer status page. deploy/bin/status.sh answers "is it serving, and is every reader on the same bundle" for an operator with access to the deployment, and since ACP-301 it answers the second question against a real deployment and not only against a local stack: every bundle reader serves a read-only status route that names the customers it has activated, and the command asks each of them under one operator identity. It has a --json mode written for a status page that does not exist yet. Until it does, ask.
  • No automatic notice from us when a leg is degraded. You find out by asking, or by a refusal.
  • No credit or refund schedule. The response times in section 2 are commitments about answering, not about availability, and nothing here is a service credit.
  • Nothing is answered outside working hours today. A 24-hour channel is not part of this offer yet; when it is, this page will say so and name it.
  • No named individual. hello@ziffer.io reaches whoever is on the rota, which is deliberate: a named person is an availability risk, not a service.

Synced from ziffer docs/onboarding/support.md at 32bc4db; edit the source, never this page.

On this page