Unofficial python cleint for Wompi to create transactions.
Project description
pywompi
Cliente Python no oficial para la API de Wompi El Salvador (api.wompi.sv).
Wompi El Salvador es un producto distinto a Wompi Colombia: se autentica con OAuth2 Client Credentials en vez de public/private key, y firma sus webhooks con un esquema HMAC diferente. Este paquete está escrito específicamente para el producto salvadoreño — si necesitás Wompi Colombia, buscá otro cliente.
No es un paquete oficial de Wompi ni de Bancolombia. Es mantenido de forma independiente por Roque Studios.
Instalación
pip install pywompi
Requiere Python 3.9+.
Quickstart
import os
from pywompi import WompiClient
client = WompiClient(
client_id=os.environ["WOMPI_CLIENT_ID"], # App ID del panel de Wompi
client_secret=os.environ["WOMPI_CLIENT_SECRET"], # API Secret del panel de Wompi
)
enlace = client.create_payment_link({
"identificadorEnlaceComercio": "PEDIDO-123",
"nombreProducto": "Consulta CloudClinic",
"monto": 25.00,
})
print(enlace["urlEnlace"]) # URL para redirigir al cliente
print(enlace["urlQrCodeEnlace"]) # QR del enlace de pago
client.close()
O como context manager, para que el cliente HTTP interno se cierre solo:
with WompiClient(client_id=..., client_secret=...) as client:
transaccion = client.get_transaction("SV-1720800000-abc123")
print(transaccion["estado"])
El access token de OAuth2 se pide y se cachea en memoria automáticamente; no hace falta manejarlo a mano ni refrescarlo vos mismo.
Endpoints sin wrappear todavía
client.py solo wrappea los endpoints que están confirmados contra la
documentación oficial (Enlace de Pago, Transacción
de Compra). Para cualquier otro endpoint del Swagger de Wompi (tokenización,
cargos recurrentes, datos de negocio, etc.), usá el método genérico ya
autenticado:
resultado = client.request("GET", "DatosNegocio")
resultado = client.request("POST", "EnlacePagoRecurrente", json={...})
Validar webhooks
Wompi firma cada webhook con el header wompi_hash: el HMAC-SHA256 del
body crudo de la petición, usando tu API Secret como llave. Nunca
proceses un webhook sin validar esta firma primero — cualquiera puede
mandarte un POST diciendo que una transacción fue aprobada si no la validás.
from pywompi import parse_event, WompiWebhookError
def wompi_webhook_view(request):
try:
event = parse_event(
raw_body=request.body, # bytes CRUDOS, no el dict ya parseado
received_hash=request.headers.get("wompi_hash", ""),
api_secret=os.environ["WOMPI_CLIENT_SECRET"],
)
except WompiWebhookError:
return HttpResponse(status=400)
if event["data"]["transaccion"]["estado"] == "APROBADA":
...
⚠️ El punto que más rompe integraciones: el HMAC se calcula sobre el
body tal cual llegó por la red, byte por byte. Si tu framework ya parseó
el JSON a un dict y vos hacés json.dumps() para "reconstruirlo", el hash
casi seguro no va a matchear — el orden de las llaves o los espacios
pueden cambiar en la re-serialización. Siempre usá el body crudo:
| Framework | Cómo obtener el body crudo |
|---|---|
| Django | request.body (bytes, antes de acceder a request.POST) |
| FastAPI | await request.body() (no uses un parámetro Body() tipado) |
| Flask | request.get_data() |
Ver examples/ para integraciones completas de Django y FastAPI.
Ambientes (sandbox / producción)
A diferencia de Wompi Colombia, la documentación pública de Wompi El Salvador no expone subdominios separados de sandbox/producción — el ambiente se determina por el App ID / API Secret que uses (cada aplicativo se marca como productivo o no desde el panel). Si tu cuenta sí tiene URLs distintas, pasalas explícitamente:
client = WompiClient(
client_id=...,
client_secret=...,
token_url="https://id.wompi.sv/connect/token",
api_base_url="https://api.wompi.sv",
)
Manejo de errores
from pywompi.exceptions import (
WompiError, # excepción base
WompiAuthError, # falló la autenticación OAuth2
WompiConnectionError, # error de red / timeout
WompiAPIError, # Wompi respondió con status >= 400
WompiWebhookError, # firma de webhook inválida
)
try:
client.create_payment_link({...})
except WompiAPIError as e:
print(e.status_code, e.payload) # inspeccionar la respuesta de error
except WompiConnectionError:
# reintentar, encolar para retry, etc.
...
Desarrollo
git clone https://github.com/roquestudios/pywompi
cd pywompi
pip install -e ".[dev]"
ruff check .
ruff format .
mypy src/pywompi
pytest
Licencia
GPL — ver LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pywompi-0.1.0.tar.gz.
File metadata
- Download URL: pywompi-0.1.0.tar.gz
- Upload date:
- Size: 29.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70ca7e02f919fc1d0ae9d5150474ab87dbd8b2f17a416448d971bb77624424fc
|
|
| MD5 |
35a9d1438f0686c1be7b7932319117f4
|
|
| BLAKE2b-256 |
3c6333ccdbe87656d77c25f2da6c1fcf81c887db8374a3c742931cbe8ca609f1
|
Provenance
The following attestation bundles were made for pywompi-0.1.0.tar.gz:
Publisher:
ci.yml on Roque-Studios/pywompi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pywompi-0.1.0.tar.gz -
Subject digest:
70ca7e02f919fc1d0ae9d5150474ab87dbd8b2f17a416448d971bb77624424fc - Sigstore transparency entry: 2165180195
- Sigstore integration time:
-
Permalink:
Roque-Studios/pywompi@40a0887224a5790e285b8ec85d630eb887e231b4 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Roque-Studios
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@40a0887224a5790e285b8ec85d630eb887e231b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pywompi-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pywompi-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7931f1588c2fc1b61e53c78b9c7e7f4a28bd19ccded636ce2b5dbbfe7076a94
|
|
| MD5 |
345eb3b4db5c12769455f6049829cd79
|
|
| BLAKE2b-256 |
5e572de991ef697f6135e7bdf46b576576a945ab206bd72a698a48618f751a8b
|
Provenance
The following attestation bundles were made for pywompi-0.1.0-py3-none-any.whl:
Publisher:
ci.yml on Roque-Studios/pywompi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pywompi-0.1.0-py3-none-any.whl -
Subject digest:
c7931f1588c2fc1b61e53c78b9c7e7f4a28bd19ccded636ce2b5dbbfe7076a94 - Sigstore transparency entry: 2165180200
- Sigstore integration time:
-
Permalink:
Roque-Studios/pywompi@40a0887224a5790e285b8ec85d630eb887e231b4 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Roque-Studios
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@40a0887224a5790e285b8ec85d630eb887e231b4 -
Trigger Event:
push
-
Statement type: