# IIdempotencyStore

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.iidempotencystore/
> Summary: IIdempotencyStore: The store for idempotency records.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Abstractions.dll</code></div>

The store for idempotency records.

```csharp
public interface IIdempotencyStore
```

## Remarks

A request that carries an `Idempotency-Key` header is processed **at most
once**, exactly as the HTTP `Idempotency-Key` standard (the pattern
Stripe follows) prescribes: while the first request is running, a second request
with the same key either gets the stored response, or (if still processing) gets
`409`.

The default (in-memory) setup registers the first-class
`InMemoryIdempotencyStore`; it is sufficient for a single-instance deployment.
A multi-instance deployment requires a SQL provider — otherwise each instance keeps
its own key set and deduplication is lost across instances.

## Methods

### <a id="Tracon_IIdempotencyStore_CompleteAsync_System_String_System_String_Tracon_IdempotencyResponse_System_Threading_CancellationToken_"></a> CompleteAsync\(string, string, IdempotencyResponse, CancellationToken\)

Records the completed response and sets the key's state to `Completed`.

```csharp
ValueTask CompleteAsync(string tenantId, string key, IdempotencyResponse response, CancellationToken cancellationToken = default)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The tenant identifier.

`key` [string](https://learn.microsoft.com/dotnet/api/system.string)

The key.

`response` [IdempotencyResponse](/api/tracon.idempotencyresponse/)

The response to store.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask)

### <a id="Tracon_IIdempotencyStore_ReleaseAsync_System_String_System_String_System_Threading_CancellationToken_"></a> ReleaseAsync\(string, string, CancellationToken\)

Deletes the record after a failed request; a retry with the same key
becomes free again.

```csharp
ValueTask ReleaseAsync(string tenantId, string key, CancellationToken cancellationToken = default)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The tenant identifier.

`key` [string](https://learn.microsoft.com/dotnet/api/system.string)

The key.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask)

#### Remarks

A failed run's record is not kept. The purpose of idempotency is to
make retries safe; keeping a failure would mean the client can never
retry after a transient error.

### <a id="Tracon_IIdempotencyStore_ReserveAsync_Tracon_IdempotencyRequest_System_Threading_CancellationToken_"></a> ReserveAsync\(IdempotencyRequest, CancellationToken\)

Tries to reserve the key as `Reserved`. If the key already exists,
the existing record's state is returned and no new record is OPENED.

```csharp
ValueTask<IdempotencyReservation> ReserveAsync(IdempotencyRequest request, CancellationToken cancellationToken = default)
```

#### Parameters

`request` [IdempotencyRequest](/api/tracon.idempotencyrequest/)

The reservation request.

`cancellationToken` [CancellationToken](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken)

The cancellation token.

#### Returns

 [ValueTask](https://learn.microsoft.com/dotnet/api/system.threading.tasks.valuetask\-1)<[IdempotencyReservation](/api/tracon.idempotencyreservation/)\>

The reservation result.

#### Remarks

The reservation must be **atomic**: if two concurrent
requests arrive with the same key, only one must get
[IdempotencyState.Reserved](/api/tracon.idempotencystate/), the other
[IdempotencyState.InProgress](/api/tracon.idempotencystate/).
