A payment partner demands a 24-hour freshness window so its late retries are never rejected — what do you agree to?
answer
- Two costs, two organisations
- Separate late delivery from double execution
- The window and the memory move together
- Price it rather than refuse it
- Test keys must not verify in production
basics
~20 sAgree only if remembered-identifier retention is extended to cover the whole window, because a window without matching memory is pure exposure. Price the extra storage, write the retention bound into the interface agreement, and keep partner test keys unacceptable in production.
solid answer
~50 sFirst separate the two things the partner has conflated: tolerance for *late delivery* and permission to *execute the same instruction twice*. Only the first is negotiable. A 24-hour window is safe if the receiver remembers accepted identifiers for at least 24 hours — then a copy is either too old or already seen. So the real price of the request is storage and clock accuracy, not risk, which turns a refusal into a cost you can quote. What you must not concede: dedupe on a value the partner regenerates per attempt, retention shorter than the window, or acceptance of messages signed by their test keys. Then put the numbers in the interface agreement — window, retention, key scope — and name who absorbs a duplicated payment, because the false-rejection cost lands on them while the duplicate-execution cost lands on you.
go deeper
Know that a longer acceptance window means a captured message stays usable for longer, and that somebody has to decide how long is acceptable. It is not a value chosen for convenience alone.
Be able to say why the window and the remembered-identifier retention must move together, and to compute the exposed interval when retention is shorter than the window.
Turn the demand into a costed option: quote the storage for matching retention, name the non-negotiables, and identify the cross-environment key scope that removes the captured-traffic case entirely.
Own the asymmetry — rejection cost falls on the partner, duplicate-execution cost falls on you — and settle it in the interface agreement: coupled window and retention with named approvers, key scope as a partner obligation, and explicit liability for a duplicated payment.
## Why this is a negotiation, not a configuration change The partner is not asking for a setting. They are asking you to accept older instructions, and every honest answer costs somebody something. The engineering content of the decision is small; the difficulty is that the two costs land on different organisations. - **A narrow window** pushes cost onto the partner: their late batch runs, their queue backlogs and their clock drift turn into rejected instructions, operational escalation and manual re-sends. - **A wide window** pushes cost onto you: either storage to remember everything for the window's length, or exposure to a copy being executed twice. A lead who states that asymmetry out loud changes the conversation, because the partner is currently proposing that you absorb their operational problem without knowing they are. ## The technical reframing that unlocks it A timestamp window is an *expiry* rule, not a duplicate check. Inside it, the same message is accepted every time it arrives. So "24-hour window" is only a risk statement if the window is the only freshness mechanism. Pair it with a remembered-identifier set whose retention is at least as long as the window, and the composition holds: a copy is refused because it is too old, or refused because it has already been seen, with no interval in between. That converts the partner's demand into an arithmetic problem you can put a number on: messages per day multiplied by identifier size multiplied by retention, plus the lookup cost on the hot path. For most partner payment volumes this is trivially small, which means the correct answer is very often *yes, and here is what it costs* rather than a principled refusal. Refusing on principle when the cost is a few gigabytes is the failure mode that gets the security position overruled later, at a worse moment, by someone senior enough to simply widen the window without the retention. The corollary is the trap: agreeing to the window and *not* extending retention. A 24-hour window with one hour of memory leaves 23 hours in which any held copy executes again. That is strictly worse than the position you started from, and it is the outcome of a decision made by two teams a month apart. ## What is genuinely not negotiable 1. **The deduplication key must be under the signature and must name the instruction, not the transmission.** If the partner regenerates the value per attempt, your memory cannot function no matter how long retention runs, and the window becomes the only control again. 2. **Retention greater than or equal to the window**, stated as a single coupled pair. Write them in the same sentence of the interface agreement so neither can be changed alone. 3. **Key scope by environment.** The partner's integration harness replaying yesterday's captured production traffic into your production endpoint is indistinguishable, message by message, from a deliberate second execution by an insider who holds the same copies: authentic content, valid signature, no boundary crossed. Freshness state may catch it if retention covers the age of the captured traffic, but the durable control is that production refuses anything signed by a test key, and that the audience field inside the signed content names the production receiver. That is a control class — removing the credential the technique depends on — rather than a tolerance setting. ## The organisational half Three things belong in the agreement rather than in code: - **The coupled pair.** Window and retention, with a named owner on your side who must approve any change to either. - **Liability for a duplicate.** Who absorbs a payment executed twice when the partner's own system emitted the second copy? This is the question that makes the partner care about their retry discipline, and it is the reason the conversation belongs with a contract owner and not only with their integration engineer. - **Key scope and environment separation**, as an obligation on the partner, so that their harness cannot produce a message your production receiver would ever verify. ## What good sounds like "Yes to 24 hours, provided we hold accepted identifiers for 25 and the identifier is inside your signed content and stable across your retries. That costs us roughly *X* of storage, which we will absorb. In exchange we need your test keys scoped out of production and the window/retention pair written into the interface schedule, with a named approver each side. And we should agree now who wears a duplicated payment, because at 24 hours the most likely cause of one is your retry path, not an attacker." That answer prices the request, closes the hole the request would otherwise open, converts one control into a contractual obligation, and puts the residual loss with the party that can prevent it.
- The partner's test harness replays yesterday's captured production traffic into production by mistake. Is that a different problem?Mechanically it is the same one: authentic content, valid signature, nothing forged, so every check passes and only receiver-held memory can refuse it. The difference is the durable fix. Freshness state helps only if retention covers the age of the captured traffic, whereas scoping keys by environment and binding an audience identifier inside the signed content means a production receiver can never verify a test-signed message at all.
- Where does the cost of a narrow window actually land, and why does that matter in the negotiation?On the partner's operations — rejected late batches, escalations, manual re-sends — while the cost of a wide window lands on you as storage or as duplicate execution. Naming that asymmetry stops the discussion being framed as your caution against their productivity. It also identifies who should be in the room: someone who can commit their side to retry discipline, not only their integration engineer.
- You are overruled and the window is widened without extending retention. What is the residual position?There is now an interval equal to the window minus the retention in which any held copy executes again, and the most likely source is the partner's own retry path. State the interval as a number, record who owns it, and get the coupled pair written down so the next change cannot repeat it silently. If the number is unacceptable, the cheaper mitigation is a per-instruction value bound rather than an argument about the window.
- Is there a case for refusing the wider window outright?Yes, when retention cannot be extended to match — a constrained receiver with no room to remember a day of identifiers, or a receiver with no reliable clock, where a counter is the only mechanism available. There the window is not a tunable at all, and the honest answer is that the partner must fix delivery latency or accept ordered delivery, because there is no receiver state to buy the tolerance with.
saying these in an interview costs you the question
- Agrees to the window without extending identifier retention
- Refuses on principle without pricing the storage
- Treats freshness tolerance as a setting with no named owner
- Accepts partner test keys in production as an operational issue
- Assumes the sender's retry discipline substitutes for receiver state
- Leaves liability for a duplicated payment unstated