Void a signal (Early access)
A void takes one signal out of your usage. Use it when a signal should never have counted: a test event sent to production, a signal sent for the wrong customer, or a retry your system sent under a second key.
Early access. Signal voiding is new and still being extended.
A voided signal stops counting as usage in every billing period it was counted
in. Paid keeps the signal. By default the signal reads leave it out, and you can
read it with includeVoided=true.
A void is permanent. There is no way to un-void a signal. To correct a signal, void it and send a new one under a new idempotency key.
Prerequisites
- An organization API key with the
write:usagescope. Full-access keys have it. Voiding needs an API key; a dashboard session cannot void a signal. A void is not available through the MCP server or the in-product assistant yet. - Signal voiding turned on for your organization. Ask your Paid contact to
enable it. Until then, the void endpoints answer
404, as for a path that does not exist. That404carriesAPI_ENDPOINT_NOT_FOUNDundererror.code. A missing signal answers404withSIGNAL_NOT_FOUNDin a top-levelcodeinstead. While voiding is being turned on for you, a request can briefly get403withFEATURE_NOT_ENABLEDinstead of the404. - The signal’s ID, or the idempotency key you sent it with. Every signal in
GET /api/v2/signalscarries itsid.
Void a signal by ID
PUT /api/v2/signals/{id}/void voids the signal with that ID. The body is
optional. Send a reason of up to 500 characters if you want one kept with the
void.
Voiding twice is safe
Voiding a signal that is already voided answers 200 with the same
signalCorrectionId and alreadyVoided: true. Your usage, billing and credits
are not changed a second time, so you can repeat a void after a timeout without
checking first. A voided signal reads as not found by default, but voiding it
again still answers 200. Your audit log records the repeat. The repeat’s cells array is
empty, because the billing effects were returned when the void was first made.
Void a signal by idempotency key
PUT /api/v2/signals/idempotency-key/{idempotencyKey}/void voids the signal
you sent with that idempotency key. The answer is the same as for a void by ID.
- The key is matched exactly as stored. URL-encode it, in particular if it
contains
/,?or#. - A signal sent with a customer API key is stored under a namespaced key. Void it by its ID.
- A key that names no signal answers
404withSIGNAL_NOT_FOUND. A signal that arrived moments ago may not be stored yet, so try again shortly. - A key that names more than one signal answers
409withAMBIGUOUS_IDEMPOTENCY_KEYand voids nothing. Void the signal you mean by its ID. - A key of
.or..cannot be used in the path. An HTTP client resolves those two segments before it sends the request, so the request never names the key. Void that signal by its ID.
After a void
Reading voided signals
A voided signal is one you withdrew, so the three signal reads leave it out by default:
No signal in these default responses carries a voided field, because none
returned is voided.
Pass includeVoided=true on any of the three reads to include voided signals.
Every signal returned then carries voided: true for a voided signal and
false for any other. includeVoided=false and no value behave the same.
These reads apply to organizations with signal voiding turned on. For other
organizations, nothing is filtered, no signal carries voided, and
includeVoided is accepted and ignored.
When signal voiding is on for your organization and Paid cannot read your voided
signals, a read answers an error instead of showing a voided signal as live:
503 for the list, and 500 for the read by ID and the lookup. Try again. If
Paid cannot tell whether signal voiding is on for your organization, a read
behaves as if it were off: it leaves nothing out, and no signal carries
voided. The list answers 422 when your organization has
more voided signals than one request can leave out. Set includeVoided=true or
narrow createdAtFrom.
Resending a voided signal
A voided signal keeps its idempotency key, so a signal you resend under that key is not stored. The bulk ingest response counts it apart from duplicates:
This response comes from a batch of 3 new signals, 1 resend of an earlier signal
and 1 resend of a voided signal. voided is 0 when none apply. The four counts
add up to the number of signals in the batch, so add voided if you reconcile
the counts.
Prepaid credits
A signal can spend a customer’s prepaid credits. Voiding it gives them back:
- The ledger gets a reversal: a new entry that returns the credits to the pool they were spent from. The original spend is never edited. The reversal is recorded when you void, and it counts in the period of the original spend.
- If that pool can no longer take the credits back, for example because its
period has ended, they are forfeited and read as expired. The
forfeitedamount in the answer says how much. - Two cases are refused instead. See
CREDIT_POOL_VOIDEDandCREDIT_POOL_AMENDEDbelow.
When a void is refused
A refused void changes nothing in your usage, billing or credits. The one
exception is a 502 or 503 from a service failure, where the void may or may
not have been made: see the last rows of the table. The answer carries a code
and an error message. For a refusal about one billing period, details names
the order line and the period.
Signals counted by an activation charge
When an order is activated, a usage line priced in prepaid credits from a meter
charges the usage that came in before activation once. The charge is a single
spend that names no signal. A void of one of those signals is refused with
COVERED_BY_ACTIVATION_CHARGE, because there is no spend of that signal’s to
give back.
For example, a customer’s order is activated on 15 November, and its billing
period runs 1 to 30 November. A usage line on it is priced in prepaid credits
from a meter that sums tokens. A signal dated 10 November with 500 tokens
came in before activation. At activation, Paid charged the customer’s credits
once for all the usage of that period so far.
- Voiding the 10 November signal is refused. Nothing is voided and no credits are returned. To correct the customer, grant credits for the 500 tokens or issue a credit note.
- A signal dated 20 November, sent after activation, is charged on its own and voids as usual. One sent within about a minute of the activation charge may still be refused.
- A signal dated in October, before the period the charge covered, voids as usual.
- If the order has been deleted, a void of such a signal is accepted and returns no credits.
Settled and invoiced periods
Once a billing period is settled, no signal counted in it can be voided. A period settles when Paid closes it for invoicing. After that, the correction is a credit note, never a void.
The period that decides is the one the signal was billed in, not the date on the signal. Usage that arrived late and was carried forward into an open period is still voidable there.
A line priced from a meter that bills once per period is the exception. This
covers any such meter: count, sum, maximum, minimum, average, latest value or
unique count. For these lines, the period that holds the signal’s own time also
decides, whether or not that meter counts the signal. If the customer has such
a line and that period is settled, the void is refused with PERIOD_CLOSED.
Voiding signals that feed a workflow
A workflow groups the signals of one run, such as the steps of one agent task. A workflow meter charges it once, when it closes, by writing one charge signal.
- A step of an open workflow. An open workflow adds no refusal of its own.
The other checks in this guide still apply, for example the void limit, a
settled period and
COST_PLUS_LINE. When a void goes through, the charge, when it is written, leaves the step out. - A step of a closed workflow. The void is refused with
WORKFLOW_CLOSED. Voiding a step never voids the workflow’s charge, and Paid does not offer a way to void a step together with its charge. - The charge itself. You can void a workflow’s charge directly, like any
signal. A charge carries
_derivedin itsdata. The charge is voided, the workflow’s steps stay live, and the workflow is not charged again. The same checks apply as for any signal, for example a settled period. - Late steps. Steps that arrive after the workflow closed, or after its charge was written, are handled as they were before voiding. Voiding adds no new refusal when you send signals.
Voiding does not void other signals for you, and it does not rebuild a charge from the steps that remain.