> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stockshift.io/llms.txt
> Use this file to discover all available pages before exploring further.

# .NET

> Un cliente de .NET para la API de StockShift. Tiene un método por cada operación de la referencia de la API y un modelo para cada solicitud y respuesta. Todo se genera a partir del documento OpenAPI de la API.

Apunta a .NET 10 y .NET Standard 2.0, así que también funciona en .NET 8 y en .NET Framework 4.6.2 o posterior. Funciona con Native AOT y trimming en .NET 10.

## Instalación

```bash theme={null}
dotnet add package StockShift.Sdk
```

## Inicio rápido

Crea un artículo y luego lista las existencias disponibles:

```csharp theme={null}
using StockShift;
using StockShift.Models;

var stockshift = new StockShiftClient(Environment.GetEnvironmentVariable("STOCKSHIFT_TOKEN")!);

await stockshift.Catalog.CreateItemAsync(new CreateItemRequest
{
    Sku = "BOLT-M4",
    Name = "M4 hex bolt",
    Type = ItemType.Stocked,
    MakeOrBuy = MakeOrBuy.Buy,
});

await foreach (var row in stockshift.Inventory.ListStockOnHandAsync())
{
    Console.WriteLine($"{row.Sku} {row.LocationCode} {row.AvailableToPromise}");
}
```

Crea un solo cliente y reutilízalo. Es seguro para uso con varios hilos.

## Inyección de dependencias

En una app de ASP.NET Core o en cualquier app que use `Microsoft.Extensions.DependencyInjection`, registra el cliente con `AddStockShift()`. Envía sus llamadas a través de `IHttpClientFactory`:

```csharp theme={null}
builder.Services.AddStockShift(options => options.Token = builder.Configuration["StockShift:Token"]);
```

Luego recibe `StockShiftClient` en un constructor. `AddStockShift()` devuelve el `IHttpClientBuilder`, así que puedes agregarle tus propios handlers, como uno de registro.

## Autenticación

Pasa una clave de API o un token de acceso OAuth como token. Crea una clave de API en la app, en Configuración > Acceso > Claves de API. La clave actúa como el miembro que la creó, y cada llamada necesita tanto el permiso del miembro como uno de los alcances de la clave.

Para un token OAuth que vence, define `TokenProvider` en su lugar. El cliente lo llama antes de cada solicitud:

```csharp theme={null}
var stockshift = new StockShiftClient(new StockShiftOptions
{
    TokenProvider = cancellationToken => tokens.GetCurrentAsync(cancellationToken),
});
```

Otras opciones:

| Opción | Valor predeterminado | Significado |
| - | - | - |
| `BaseAddress` | `https://app.stockshift.io/api/v1` | Dónde está la API. |
| `MaxRetries` | `2` | Reintentos para una llamada que se puede reintentar. |
| `Timeout` | 60 segundos | Cuánto esperar en cada intento. |
| `MaxRetryAfter` | 60 segundos | El `Retry-After` más largo que vale la pena esperar. |
| `TimeProvider` | `TimeProvider.System` | El reloj para los tiempos de espera y las esperas. Reemplázalo en las pruebas. |

## Hacer llamadas

Cada área de la API es una propiedad, como `Catalog` o `Inventory`, con un método por cada operación. Primero van los parámetros de ruta, luego el cuerpo y luego la cadena de consulta. Todos los métodos reciben un `CancellationToken` al final:

```csharp theme={null}
var item = await stockshift.Catalog.GetItemAsync(itemId, cancellationToken: cancellationToken);
Console.WriteLine(item.Sku);

var page = await stockshift.Catalog.ListItemsPageAsync(new ListItemsQuery { Search = "bolt", Status = ItemStatus.Active }, cancellationToken: cancellationToken);
```

El comentario de documentación de cada método indica su ruta, como `GET /catalog/items/{item}`. Una llamada devuelve el `data` de la respuesta. Una llamada con respuesta vacía devuelve un `Task`. Una exportación CSV devuelve su texto. Un archivo o un PDF llega como un `StockShiftContent`, que contiene el flujo sin leer. Libéralo con `Dispose` cuando termines.

Un valor que pertenece a un conjunto fijo, como el tipo de un artículo, es un `string`, y el conjunto es una clase de constantes, como `ItemType`. Un valor que la API agregue después igual se lee.

Un campo de la solicitud que se puede omitir o enviar como null es un `Opt<T>`. Deja la propiedad sin asignar para omitir el campo, de modo que la API conserve lo que tiene. Asígnale `null` para enviar un null explícito:

```csharp theme={null}
// Takes the device off its location and keeps its offline grace as it is.
await stockshift.Devices.RenameDeviceAsync(deviceId, new UpdateDeviceRequest { LocationId = null }, cancellationToken: cancellationToken);
```

## Paginación

Una lista que puede crecer devuelve una página a la vez. Su método devuelve un `IAsyncEnumerable` que sigue los cursores y entrega cada registro:

```csharp theme={null}
await foreach (var found in stockshift.Catalog.ListItemsAsync(new ListItemsQuery { Search = "bolt" }))
{
    Console.WriteLine(found.Sku);
}
```

El método que termina en `PageAsync`, como `ListItemsPageAsync`, obtiene una sola página. Para paginar a mano, pasa el `NextCursor` de cada página como `After` en la consulta hasta que sea null.

## Errores

Una llamada fallida lanza una `StockShiftApiException` que contiene el cuerpo de detalles del problema de RFC 9457. Decide según `Code`, que es estable. El detalle está escrito para personas y puede cambiar.

```csharp theme={null}
try
{
    await stockshift.Catalog.CreateItemAsync(request);
}
catch (StockShiftApiException error) when (error.Code == "validation_failed")
{
    foreach (var (field, messages) in error.Errors)
    {
        Console.WriteLine($"{field}: {string.Join(" ", messages)}");
    }
}
```

`StockShiftApiException` también tiene `StatusCode`, `Problem` y `Headers`. Una llamada que no recibe respuesta, porque falló la red o el intento agotó el tiempo de espera, lanza una `StockShiftConnectionException`. Ambas extienden `StockShiftException`. Cancelar el token lanza una `OperationCanceledException`, como es habitual en .NET.

## Reintentos y claves de idempotencia

El cliente reintenta un `429` después del tiempo que indica `Retry-After`. Lo hace con todos los métodos, porque la API no ejecutó la llamada. Si `Retry-After` es mayor que `MaxRetryAfter`, lanza una excepción en lugar de esperar.

Un `5xx` o una falla de red se reintenta para `GET`, `PUT` y `DELETE`, con una breve espera entre intentos. Un `POST` o `PATCH` solo se reintenta cuando le das una clave de idempotencia, para que un reintento no pueda hacer el cambio dos veces:

```csharp theme={null}
await stockshift.Integrations.PushStockNowAsync(connectionId, new RequestOptions { IdempotencyKey = Guid.NewGuid().ToString() });
```

Usa una clave nueva para cada cambio que quieras hacer. Los endpoints que respetan la clave lo indican en la referencia de la API.

## Webhooks

Revisa el encabezado `StockShift-Signature` antes de confiar en una entrega. `StockShiftWebhook.Verify()` necesita el cuerpo sin procesar, exactamente como llegó:

```csharp theme={null}
app.MapPost("/webhooks/stockshift", async (HttpRequest request) =>
{
    using var reader = new StreamReader(request.Body);
    var payload = await reader.ReadToEndAsync();

    try
    {
        var webhookEvent = StockShiftWebhook.Verify(payload, request.Headers[StockShiftWebhook.SignatureHeader], secret);
        if (webhookEvent is InventoryStockAdjustedEvent adjusted)
        {
            Console.WriteLine($"{adjusted.Data.ItemId} {adjusted.Data.Quantity}");
        }

        return Results.NoContent();
    }
    catch (WebhookVerificationException)
    {
        return Results.BadRequest();
    }
});
```

Cada tipo de evento tiene su propia clase, como `InventoryStockAdjustedEvent`. Un tipo que este paquete aún no conoce llega como un `UnknownWebhookEvent`.

Rechaza una entrega de más de cinco minutos de antigüedad. Pasa `tolerance` para cambiarlo. Los reintentos de un evento conservan su `Id`, así que guárdalo y omite los eventos que ya procesaste.

Para probar tu propio receptor, `StockShiftWebhook.Sign()` firma un payload igual que StockShift.

## Versiones

La versión mayor cambia cuando la API cambia de una forma que puede romper tu código, como un campo eliminado o un parámetro obligatorio nuevo. Los endpoints y campos nuevos llegan en versiones menores. `StockShiftClient.ApiVersion` contiene la versión de la referencia de la API con la que se compiló el paquete.


## Related topics

- [StockShift para desarrolladores](https://docs.stockshift.io/es/index.md)
- [SDK](https://docs.stockshift.io/es/sdks/index.md)
- [Busca un producto en la biblioteca](https://docs.stockshift.io/es/api-reference/biblioteca-de-productos/busca-un-producto-en-la-biblioteca.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.