Ir al contenido
docs

Registrar un conteo de inventario

Registra lo que hay físicamente en una bodega en un instante (counted_at):

POST /public/v1/inventory/counts

Permiso inventory:write · Idempotency-Key obligatorio · Inventario

el stock oficial pasa a ser esa cantidad y las ventas ocurridas después del conteo se suman encima, nunca se pierden. Un conteo más viejo que el último registrado queda solo como historial (status: historical). Solo cuando la cuenta ya lleva el stock en la nube; si no, 409 STOCK_MODE_LEGACY. Emite el webhook inventory.count.created.

Parámetros

Encabezados

NombreTipoRequeridoDescripción
Idempotency-KeystringSíObligatorio en todo POST. Un valor único por operación (p. ej. un UUID); reutilízalo solo para reintentar la MISMA operación. Válido 24 h. Máximo 255 caracteres. Formato: ^[A-Za-z0-9_\-:.]{1,255}$.

Cuerpo de la petición

JSON (Content-Type: application/json): un objeto StockCountCreate.

Un campo que no esté en la lista se rechaza con VALIDATION_ERROR.

CampoTipoRequeridoDescripción
product_idstring (uuid)Sí—
variant_idstring (uuid)NoObligatorio si el producto tiene variantes.
warehouse_idstring (uuid)NoPor defecto, la bodega predeterminada (o la única bodega activa).
counted_quantitynumberSíLo que hay físicamente, en la unidad base del producto. Entero, salvo en productos que se venden por peso (sold_by_weight), que aceptan decimales. Mínimo: 0. Máximo: 1000000000.
counted_atstring (date-time)NoCUÁNDO se contó (no cuándo se envía), ISO 8601 con zona. Nunca en el futuro. Por defecto, ahora. Las ventas ocurridas después se suman encima.
notestringNoNota visible en el historial del conteo. Máximo 500 caracteres.

Ejemplo de petición

El cuerpo del ejemplo lleva solo los campos obligatorios, con valores ilustrativos: ajústalos a tus datos.

Terminal
curl -X POST "https://api.posdata.so/public/v1/inventory/counts" \
  -H "Authorization: Bearer $POSDATA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"product_id":"3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d","counted_quantity":5}'
JavaScript
const res = await fetch('https://api.posdata.so/public/v1/inventory/counts', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.POSDATA_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(), // reutilízala solo para reintentar
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "product_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
    "counted_quantity": 5
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message} (${data.error.request_id})`);
Python
import os
import uuid

import requests

res = requests.post(
    "https://api.posdata.so/public/v1/inventory/counts",
    headers={
        "Authorization": f"Bearer {os.environ['POSDATA_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),  # reutilízala solo para reintentar
    },
    json={
        "product_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
        "counted_quantity": 5,
    },
    timeout=30,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{data['error']['code']}: {data['error']['message']} ({data['error']['request_id']})")
PHP
<?php
$ch = curl_init('https://api.posdata.so/public/v1/inventory/counts');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('POSDATA_API_KEY'),
        'Idempotency-Key: ' . bin2hex(random_bytes(16)), // reutilízala solo para reintentar
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'product_id' => '3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d',
        'counted_quantity' => 5,
    ]),
]);
$data = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
    throw new RuntimeException("{$data['error']['code']}: {$data['error']['message']} ({$data['error']['request_id']})");
}
Idempotency-Key
Usa un valor nuevo por operación y repite el mismo solo para reintentar esa misma operación. Mira Idempotencia.

Respuesta

201 Creado: un objeto StockCount.

CampoTipoRequeridoDescripción
object"stock_count"Sí—
idstring (uuid)Sí—
warehouse_idstring (uuid)Sí—
product_idstring (uuid)Sí—
variant_idstring (uuid) | nullSí—
counted_quantitynumberSíLo que había físicamente.
counted_atstring (date-time)SíCuándo se contó.
sourcestringSícount, count_sheet, initial, upgrade, migration o api.
statusstringSíapplied: es la base del stock oficial desde su counted_at. historical: se guardó solo como historial (ya había un conteo más reciente). pending: la cuenta todavía no lleva el stock en la nube (una caja lo registró antes del cambio); se tendrá en cuenta cuando la cuenta pase al stock en la nube. Valores: applied, historical, pending.
estimatedbooleanSí—
expected_quantitynumber | nullSíLo que el sistema creía en el instante del conteo.
differencenumber | nullSícounted_quantity − expected_quantity.
notestring | nullSí—
created_atstring (date-time)Sí—
Ejemplo de respuesta (valores ilustrativos)
{
  "object": "stock_count",
  "id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
  "warehouse_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
  "product_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
  "variant_id": "3f1c2e8d-7a10-4d0b-9a57-0b6f2f0e5c1d",
  "counted_quantity": 5,
  "counted_at": "2026-09-28T15:04:05.000Z",
  "source": "texto",
  "status": "applied",
  "estimated": true,
  "expected_quantity": 5,
  "difference": 1,
  "note": "texto",
  "created_at": "2026-09-28T15:04:05.000Z"
}

Errores

Todo error responde con un objeto Error y un request_id. Ramifica por error.code, nunca por el mensaje.

Cuerpo: un objeto Error. Qué significa cada código y qué hacer: Errores.

VALIDATION_ERRORINVALID_JSONINVALID_CURSOR

Cuerpo: un objeto Error. Qué significa cada código y qué hacer: Errores.

UNAUTHENTICATEDINVALID_API_KEYAPI_KEY_REVOKEDAPI_KEY_EXPIREDAPI_KEY_WRONG_ENVIRONMENTACCOUNT_INACTIVE

Cuerpo: un objeto Error. Qué significa cada código y qué hacer: Errores.

PLAN_REQUIREDINSUFFICIENT_SCOPEBROWSER_REQUESTS_NOT_ALLOWED

Cuerpo: un objeto Error. Qué significa cada código y qué hacer: Errores.

CONFLICTSKU_ALREADY_EXISTSIDEMPOTENCY_IN_PROGRESSNO_WAREHOUSEDEVICES_OUTDATEDINSUFFICIENT_STOCKSTOCK_MODE_LEGACY

Cuerpo: un objeto Error. Qué significa cada código y qué hacer: Errores.

IDEMPOTENCY_KEY_REUSEDCOMPOSITE_STOCK_UNSUPPORTED

Cuerpo: un objeto Error. Qué significa cada código y qué hacer: Errores.

RATE_LIMITED

Cuerpo: un objeto Error. Qué significa cada código y qué hacer: Errores.

INTERNAL_ERROR