# Lifecycle

> The life of a transaction and its enrichments, from the first call to the expiry of the content: replays, refreshes, the current result, the 90-day purge and what survives.

This page follows one transaction over time. It assumes the calls carry an `external_transaction_id` and an `Idempotency-Key`, as recommended.

## Timeline

| When | Event | What the client sees |
|---|---|---|
| Day 0, first call | Creation: Noryo computes, settles, memorises the response under the `Idempotency-Key`, records the transaction and its economic input | `200`, `enr_A`, the result's status, `usage` |
| Day 0, retry with the same key | Idempotent replay | `200`, same body, `Noryo-Idempotency-Replayed: true` |
| Day 0 to day 0 + 24 h | The key stays bound to this request | Another request with the same key: `409 idempotency_key_reuse` |
| After 24 h | The idempotency memory expires | The key is free; the transaction itself remains known |
| Any time, same transaction sent again | Economic deduplication | `200`, current result, `deduplicated: true`, not billed |
| Any time, refresh | New computation of the same transaction | `200`, **new** `enr_B`, `Location` header |
| Day 0 + 90 days | The content of each result is purged at the end of its retention | `GET`: `410 result_content_expired` |
| After the purge, same transaction sent again | The transaction is known, its content is not | `410 result_content_expired` |
| After the purge, refresh | New computation, new content | `200`, new `enrichment_id`, billed if it succeeds |

The 90-day retention applies to the content of each result; a result produced by a refresh has its own retention period. A `not_found` result has no content: it is never purged and never returns `410`.

## The current result

A transaction always has a current result, the one that sending it again returns through deduplication:

- to begin with, it is the result of the creation, whatever its status (`resolved`, `partial` or `not_found`);
- a refresh that succeeds (`refresh_recalculated`) replaces it;
- a `partial` or `not_found` refresh is recorded with its own `enrichment_id`, but does not replace it;
- an engine failure (`503 engine_error`) creates no result and replaces nothing: the `enrichment_id` its body carries only designates the failed attempt.

## Each `enrichment_id` is frozen

```text
enr_A  ──>  result of the creation   (always readable as it is until its purge)
enr_B  ──>  result of the refresh    (becomes the current result if refresh_recalculated)
```

A `GET` read returns the result of the identifier requested, never another one. To follow a transaction's latest result, record the identifier returned by each refresh.

## What survives the purge

| Item | After 90 days |
|---|---|
| Result content (`merchant`, readable status) | Purged |
| `enrichment_id` | Kept: it returns `410`, not `404` |
| Economic identity of the transaction | Kept: deduplication and refresh remain possible |
| Ledger line, units, price, accounting timestamps | Kept: you can still prove what you bought and when |
| Raw descriptor | Never retained, at any point |

## Without `external_transaction_id`

An enrichment created with an `Idempotency-Key` alone has a shorter life: it can be replayed for 24 hours and read for 90 days, but it is attached to no transaction. It is not deduplicated and cannot be refreshed (`409 refresh_not_available`).

See also [Refresh](https://developer.noryo.app/en-GB/merchant/refresh) and [Retention and 410](https://developer.noryo.app/en-GB/merchant/retention).

---

Canonical page: https://developer.noryo.app/en-GB/merchant/enrichments/lifecycle
