Zavora · SDK de Python
Tu negocio en Zavora desde Python: pedidos, catálogo, inventario, compradores, citas y mensajes. Y las herramientas listas para dárselas a un agente.
pip install zavora
Empezar
from zavora import Zavora
z = Zavora() # lee ZAVORA_API_KEY del entorno
yo = z.me() # llamada 1: qué puede hacer esta llave
print(yo["tenant"]["name"], yo["scopes"])
for pedido in z.orders.iter_all(status="paid"):
print(pedido["id"], pedido["total_amount"])
La llave se crea en el panel: Integraciones → API y webhooks, con los
permisos que quieras. z.me() te dice cuáles quedaron concedidos, así sabes
qué puedes hacer antes de intentarlo y chocar con un 403.
Lo que hay
z.products.list(limit=50) z.products.get(id)
z.products.create(name="Panela", price=3500)
z.products.update(id, price=4000)
z.orders.list(status="paid") z.orders.get(id)
z.orders.create(buyer_id=…, items=[{"product_id": …, "quantity": 2}])
z.orders.update(id, status="delivered") # o dispatch_stage="en_camino"
z.buyers.list() z.buyers.get(id)
z.buyers.create(whatsapp_number="+57300…", name="Ana")
z.adjust_inventory(product_id, delta=-3, note="rotura")
z.availability("2026-09-20")
z.schedule(buyer_id=…, scheduled_at="2026-09-20T09:00")
z.send_message(buyer_id, "Tu pedido va en camino 🚚")
Cada método vive detrás de su scope. .iter_all() recorre todas las páginas
solo — el cursor no se toca a mano.
Probar sin romper nada
Crea una llave de prueba en el panel (zvk_test_…) y úsala igual:
z = Zavora("zvk_test_…")
z.me()["sandbox"] # True
z.orders.create(...) # responde 201… y no guarda nada
Valida todo contra la base de verdad —permisos, plan, topes, stock, aislamiento—
y no confirma ni un cambio. Tampoco le manda WhatsApp a nadie: send_message
responde status: "simulated".
Errores
Cada cosa que puede salir mal tiene su excepción, para que no haya que comparar strings:
from zavora import SinPermiso, Conflicto, TopeAlcanzado
try:
z.send_message(buyer_id, "hola")
except SinPermiso:
print("a esta llave le falta el scope write:messages")
except Conflicto as e:
if e.code == "window_closed":
print("pasaron más de 24 h desde su último mensaje")
except TopeAlcanzado as e:
print("ir más despacio:", e.retry_after, "segundos")
Todas heredan de ErrorZavora.
Reintentos
Se reintenta solo lo que no cambió nada: un error de red antes de que el
servidor contestara, un 5xx o un 429 (respetando su Retry-After), con
backoff exponencial y jitter.
Una escritura sin Idempotency-Key nunca se reintenta: si el servidor
alcanzó a aplicarla y la respuesta se perdió, repetirla crearía un segundo
pedido. create() manda la clave sola, así que esas sí se reintentan seguras.
Agentes
from zavora import Zavora
from zavora.agents import ZavoraTools
tools = ZavoraTools(Zavora())
respuesta = claude.messages.create(
model="claude-opus-5",
tools=tools.anthropic(), # o tools.openai()
messages=[{"role": "user", "content": "¿Cuánto vendimos y qué falta despachar?"}],
)
for bloque in respuesta.content:
if bloque.type == "tool_use":
resultado = tools.run(bloque.name, bloque.input)
Trece herramientas con descripciones que dicen cuándo usar cada una, no solo qué hacen — que es lo que un modelo necesita para elegir bien.
Las escrituras ensayan primero. Con confirm=False (el defecto) la
herramienta devuelve lo que haría sin tocar nada:
tools.run("zavora_create_order", {"buyer_id": b, "items": [...]})
# {"dry_run": True, "would_do": {...},
# "next_step": "Enséñaselo a la persona y vuelve a llamar con confirm=true."}
El agente enseña el ensayo, la persona aprueba, y recién ahí va
confirm=True. tools.writes() lista cuáles cambian algo, por si quieres
pedir aprobación humana solo en esas.
tools.run() nunca lanza: un error de la API vuelve como {"error": {...}}
para que el agente lo lea y reaccione en vez de tumbar el bucle.
Asíncrono
from zavora import AsyncZavora
async with AsyncZavora() as z:
async for pedido in z.orders.iter_all():
...
Configuración
| Variable | Para qué |
|---|---|
ZAVORA_API_KEY |
La llave (zvk_live_…). |
ZAVORA_API_URL |
Apuntar a otro servidor. Por defecto, producción. |
También por argumento: Zavora(api_key=…, base_url=…, timeout=20, max_retries=2).
Referencia
La especificación OpenAPI está en GET /api/v1/openapi.json, y la guía en
docs/integraciones/API-PUBLICA-V1.md.
Release files for zavora 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| zavora-0.1.0.tar.gz | 16.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| zavora-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.0 kB
Release files / zavora-0.1.0.tar.gz
| Download URL | zavora-0.1.0.tar.gz |
|---|---|
| Size | 16.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
77e56fad3d787b625c20e19a9718ce188bef957ad3ab941de6eaeb65f9991d8b
|
|
BLAKE2b-256 checksum How to use checksums |
3e201fedc225e0fee84a5cb9bb819a0b3dbebb196f9f8dc9d509706fb48d1112
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / zavora-0.1.0-py3-none-any.whl
| Download URL | zavora-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6dad1c0a47cf628403863f7d74bfb27a43c85e8cb9727f63f76a9f2d8a8defe2
|
|
BLAKE2b-256 checksum How to use checksums |
26801754f4aab95c6f130e30c6845f3afa02ef5b933cdd7707103f925e50e2cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|