Saltar al contenido
ShopentlyLearn

Crear · Ajuste de existencias — Inventario

Ejecuta «Crear · Ajuste de existencias» en «Inventario» con los datos descritos a continuación.

POST/api/v1/inventory/stock-adjustments

Autenticación
Bearer
Disponible desde
STANDARD
Permisos necesarios
inventory.stock:update

Ejemplos de código

Ejemplo de solicitud

cURL

: "${SHOPENTLY_SHOP_URL:?}"

curl --disable --globoff --fail-with-body --silent --show-error \
  --proto '=https' --connect-timeout 5 --max-time 30 \
  --request POST \
  --header "Authorization: Bearer ${SHOPENTLY_ACCESS_TOKEN:?}" \
  --header 'Idempotency-Key: example-create_adjustment_api_v1_inventory_stock_adjustments_post' \
  --header 'Content-Type: application/json' \
  --data-raw '{
  "expected_version": 0,
  "locations": [
    {
      "location_id": "example",
      "on_hand": 1
    }
  ],
  "reason": "Example",
  "target_id": "example",
  "target_type": "product",
  "warehouse_id": "example"
}' \
  --url "${SHOPENTLY_SHOP_URL%/}"/api/v1/inventory/stock-adjustments

PHP

<?php
declare(strict_types=1);

$baseUrl = rtrim(getenv('SHOPENTLY_SHOP_URL') ?: '', '/');
$origin = parse_url($baseUrl);
if (!$origin || ($origin['scheme'] ?? '') !== 'https' || empty($origin['host']) ||
    isset($origin['user'], $origin['pass']) || isset($origin['user']) || isset($origin['path']) ||
    isset($origin['query']) || isset($origin['fragment'])) {
    throw new RuntimeException('SHOPENTLY_SHOP_URL must be an HTTPS origin');
}
$credential = getenv('SHOPENTLY_ACCESS_TOKEN') ?: '';
if ($credential === '' || strpbrk($credential, "\r\n") !== false) {
    throw new RuntimeException('Invalid credential');
}
$headers = ['Idempotency-Key: example-create_adjustment_api_v1_inventory_stock_adjustments_post', 'Content-Type: application/json'];
$headers[] = 'Authorization: Bearer ' . $credential;
$responseHeaders = [];
$handle = curl_init($baseUrl . '/api/v1/inventory/stock-adjustments');
curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_PROTOCOLS => CURLPROTO_HTTPS,
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_SSL_VERIFYHOST => 2,
    CURLOPT_CONNECTTIMEOUT => 5,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HEADERFUNCTION => static function ($handle, string $line) use (&$responseHeaders): int {
        if (str_contains($line, ':')) {
            [$name, $value] = explode(':', $line, 2);
            $responseHeaders[strtolower(trim($name))] = trim($value);
        }
        return strlen($line);
    },
]);
curl_setopt($handle, CURLOPT_POSTFIELDS, '{
  "expected_version": 0,
  "locations": [
    {
      "location_id": "example",
      "on_hand": 1
    }
  ],
  "reason": "Example",
  "target_id": "example",
  "target_type": "product",
  "warehouse_id": "example"
}');
$raw = curl_exec($handle);
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
$error = curl_error($handle);
curl_close($handle);
if ($raw === false) {
    throw new RuntimeException('Transport error: ' . $error);
}
if ($status < 200 || $status >= 300) {
    throw new RuntimeException('HTTP ' . $status . '; request_id=' .
        ($responseHeaders['x-request-id'] ?? '') . '; retry_after=' . ($responseHeaders['retry-after'] ?? ''));
}
$result = $raw === '' ? null : json_decode($raw, true, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
echo json_encode($result, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), PHP_EOL;

Python

from contextlib import ExitStack
import json
import os
from urllib.parse import urlsplit

import requests  # python -m pip install requests

base_url = os.environ["SHOPENTLY_SHOP_URL"].rstrip("/")
origin = urlsplit(base_url)
if origin.scheme != "https" or not origin.hostname or origin.username or origin.password or origin.path or origin.query or origin.fragment:
    raise ValueError("SHOPENTLY_SHOP_URL must be an HTTPS origin")
credential = os.environ['SHOPENTLY_ACCESS_TOKEN']
if not credential or "\r" in credential or "\n" in credential:
    raise ValueError("Invalid credential")
headers = {'Idempotency-Key': 'example-create_adjustment_api_v1_inventory_stock_adjustments_post'}
headers["Authorization"] = 'Bearer' + " " + credential
body = '{\n  "expected_version": 0,\n  "locations": [\n    {\n      "location_id": "example",\n      "on_hand": 1\n    }\n  ],\n  "reason": "Example",\n  "target_id": "example",\n  "target_type": "product",\n  "warehouse_id": "example"\n}'
if body is not None:
    headers["Content-Type"] = "application/json"

with ExitStack() as stack:
    session = stack.enter_context(requests.Session())
    files = None
    if False:
        image = stack.enter_context(open(os.environ["SHOPENTLY_IMAGE_FILE"], "rb"))
        if os.fstat(image.fileno()).st_size > 5242880:
            raise ValueError("Image exceeds 5 MiB")
        files = {"file": ("article.png", image, "image/png")}
    response = session.request(
        'POST', base_url + '/api/v1/inventory/stock-adjustments', headers=headers,
        data=body.encode("utf-8") if body is not None else None, files=files,
        timeout=(5, 30), allow_redirects=False,
    )
    if not 200 <= response.status_code < 300:
        raise RuntimeError(f"HTTP {response.status_code}; request_id={response.headers.get('X-Request-ID', '')}; retry_after={response.headers.get('Retry-After', '')}")
    if False:
        if response.headers.get("Content-Type") != "image/webp" or len(response.content) > 5242880:
            raise ValueError("Unexpected image response")
        with open(os.environ["SHOPENTLY_OUTPUT_FILE"], "xb") as output:
            output.write(response.content)
    else:
        result = response.json() if response.content else None
        print(json.dumps(result, ensure_ascii=False, indent=2))

Ejemplo de respuesta 201

JSON
{
  "data": {
    "deleted": false,
    "id": "stock_v1_WyJleGFtcGxlIiwicHJvZHVjdCIsImV4YW1wbGUiXQ",
    "version": 1
  },
  "meta": {
    "request_id": "example"
  }
}

Cómo funciona

  • Los registros de existencias distinguen la cantidad física on_hand, las reservas de pedidos, las reservas manuales y la cantidad disponible para la venta.
  • Utiliza el identificador y la versión de existencias devueltos; las existencias de productos y variantes son destinos diferentes.
  • Un sellable_limit de -1 significa ilimitado, mientras que 0 significa que no hay disponibilidad para la venta.
  • La disponibilidad ilimitada se representa con null en available.
  • No interpretes null como cero.
  • Los ajustes, límites de venta y reservas manuales tienen operaciones y permisos independientes.

Parámetros

Encabezados de solicitud

Idempotency-KeyCadena de textoObligatorio

Identificador único de una operación lógica de escritura.

minLength: 1maxLength: 128
Restricciones
pattern
"^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$"
Ejemplo: "example-create_adjustment_api_v1_inventory_stock_adjustments_post"

Cuerpo de la solicitud

application/json · Obligatorio

StockAdjustmentCreate
expected_versionNúmero enteroObligatorio

Versión leída antes de escribir; si no coincide, se rechaza la actualización.

minimum: 0maximum: 9223372036854775807
Ejemplo: 0
locationsLista <LocationQuantity > Obligatorio

Ubicaciones del almacén.

minItems: 1maxItems: 100
Ejemplo: [{"location_id":"example","on_hand":1}]
reasonCadena de textoObligatorio

Motivo registrado para el cambio.

minLength: 1maxLength: 500
Ejemplo: "Example"
target_idCadena de textoObligatorio

Identificador del producto o variante afectado por la operación.

Restricciones
pattern
"^[a-z0-9][a-z0-9_-]{0,62}$"
Ejemplo: "example"
target_typeCadena de textoObligatorio

Indica si la operación afecta a un producto o a una variante.

Restricciones
enum
["product", "variant"]
Ejemplo: "product"
warehouse_idCadena de textoObligatorio

Identificador del almacén.

Restricciones
pattern
"^[a-z0-9][a-z0-9_-]{0,62}$"
Ejemplo: "example"

Respuestas

Respuesta 200

dataMutationData Obligatorio

Contenido de una respuesta correcta.

Campos · data
deletedBooleanoObligatorio

Indica si se aplicó la eliminación.

idCadena de textoObligatorio

Identificador del recurso; consérvalo tal como se devuelve.

versionNúmero entero nullObligatorio

Versión del recurso utilizada para controlar cambios simultáneos.

metaContextPageMeta ContextMeta PageMeta RequestMeta Obligatorio

Metadatos de la respuesta.

Campos · meta

ContextPageMeta

localeCadena de textoObligatorio

Idioma seleccionado para esta solicitud.

market_codeCadena de textoObligatorio

Código del mercado devuelto por el endpoint de contexto.

market_idCadena de textoObligatorio

Identificador del mercado devuelto por el endpoint de contexto.

paginationPagination Obligatorio

Metadatos de la paginación por cursor.

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100

ContextMeta

localeCadena de textoObligatorio

Idioma seleccionado para esta solicitud.

market_codeCadena de textoObligatorio

Código del mercado devuelto por el endpoint de contexto.

market_idCadena de textoObligatorio

Identificador del mercado devuelto por el endpoint de contexto.

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100

PageMeta

paginationPagination Obligatorio

Metadatos de la paginación por cursor.

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100

RequestMeta

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100

Respuesta 201

dataMutationData Obligatorio

Contenido de una respuesta correcta.

Campos · data
deletedBooleanoObligatorio

Indica si se aplicó la eliminación.

idCadena de textoObligatorio

Identificador del recurso; consérvalo tal como se devuelve.

versionNúmero entero nullObligatorio

Versión del recurso utilizada para controlar cambios simultáneos.

metaContextPageMeta ContextMeta PageMeta RequestMeta Obligatorio

Metadatos de la respuesta.

Campos · meta

ContextPageMeta

localeCadena de textoObligatorio

Idioma seleccionado para esta solicitud.

market_codeCadena de textoObligatorio

Código del mercado devuelto por el endpoint de contexto.

market_idCadena de textoObligatorio

Identificador del mercado devuelto por el endpoint de contexto.

paginationPagination Obligatorio

Metadatos de la paginación por cursor.

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100

ContextMeta

localeCadena de textoObligatorio

Idioma seleccionado para esta solicitud.

market_codeCadena de textoObligatorio

Código del mercado devuelto por el endpoint de contexto.

market_idCadena de textoObligatorio

Identificador del mercado devuelto por el endpoint de contexto.

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100

PageMeta

paginationPagination Obligatorio

Metadatos de la paginación por cursor.

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100

RequestMeta

request_idCadena de textoObligatorio

Identificador de la solicitud; en los metadatos de respuesta identifica la solicitud HTTP.

minLength: 1maxLength: 100
Ejemplo de respuesta

Estado HTTP

200
Respuesta correcta Esquema
201
Recurso creado Esquema
400
Solicitud no válida
401
Autenticación necesaria
403
Permiso denegado
404
Recurso no encontrado
409
Conflicto de versión
422
Error de validación
429
Límite de solicitudes excedido
Otros estados HTTP (7)
405
Método no permitido
413
Solicitud demasiado grande
415
Formato no compatible
500
Error del servidor
502
Error de la puerta de enlace API
503
Servicio no disponible
504
Tiempo de espera agotado

Catálogo de errores: ErrorResponse

Cabeceras

201

LocationCadena de textoOpcional

URL relativa del recurso creado.

401

WWW-AuthenticateCadena de textoOpcional

Esquema de autenticación exigido por el servidor.

405

AllowCadena de textoOpcional

Métodos HTTP admitidos por este recurso.

429, 503

Retry-AfterNúmero enteroOpcional

Espera mínima antes de reintentar, en segundos.

minimum: 0