Skip to main content

verificar-curp

SDK oficial de Verificar CURP para Python.

  • Valida la estructura de una CURP (entidad, fecha, dígito verificador) y te dice qué está mal.
  • Coteja la CURP con los datos que ya tienes de la persona.
  • Verifica la CURP en el registro RENAPO; el resultado llega a tu webhook, correo o chat.
  • Enlaces de captura: tu cliente escribe su CURP desde su celular y el resultado llega a tu destino.
  • Verifica la firma de los webhooks que te enviamos.

Sin dependencias. Python 3.9+.

pip install verificar-curp

Uso

import os
from verificar_curp import VerificarCurpClient

client = VerificarCurpClient(api_key=os.environ["CURP_API_KEY"])

result = client.validate(
    "PEGJ850101HDFRRL04",
    persona={"nombres": "Julio", "fechaNacimiento": "1985-01-01", "sexo": "H"},
)

result.data["valida"]        # True
result.data["entidad"]       # 'Ciudad de México'
result.data["cotejo"]        # 'coincide' | 'no_coincide' | 'indeterminado'
result.data["cotejoCampos"]  # {'nombres': 'coincide', ...}
result.tokens_remaining

Una CURP mal formada no es un error: data["valida"] es False y el motivo va en data["razon"] (por ejemplo {"kind": "check-digit", "expected": "4", "actual": "9"}).

En persona, "segundoApellido": None significa "no tiene segundo apellido" y se compara; si omites la clave, no se compara.

Verificar en RENAPO

result = client.validate(
    "PEGJ850101HDFRRL04",
    verificar=True,
    destination_id="dst_...",        # panel → Destinos
    idempotency_key="cliente-123",   # opcional; nunca pongas la CURP aquí
)

v = result.verificacion
if v and v["aceptada"]:
    print("En curso:", v["job_id"])
elif v:
    print("No se pudo iniciar:", v["codigo"], "reintenta en", v["retry_after"], "s")

El resultado del registro (estatus: ACTIVA, BAJA, RNE o NO_ENCONTRADA) llega a tu destino, normalmente en segundos. También puedes consultar el estado, sin costo:

status = client.get_verification(job_id)
status.verificacion["estado"]
status.valores  # dict o None

valores llega una sola vez y se borra en la misma operación. Si tu destino ya lo recibió, aquí solo verás el estado; es la forma de recuperarlo cuando la entrega a tu destino falló.

Enlaces de captura

Un enlace de un solo uso para que tu cliente escriba su CURP desde su celular (por ejemplo, en el check-in). Si mandas los datos de la reservación en persona, la CURP se coteja contra ellos sin mostrárselos; con ask_guest_persona=True el cliente también escribe su nombre y fecha de nacimiento.

link = client.create_capture_link(
    "dst_...",
    reference="reserva-8841",  # opcional; viaja en la entrega
    persona={"nombres": "Julio", "primerApellido": "Pérez", "fechaNacimiento": "1985-01-01"},
)

link.url  # muéstralo como QR o envíalo; solo se devuelve aquí, no lo registres en logs

Crear el enlace no cuesta. Cada respuesta del cliente cuesta 1 token (hasta 3 intentos, es decir hasta 3 tokens) y solo una CURP válida que coincide llega a tu destino, como evento extraction.completed con source: "capture-link" y los campos curp, valida, entidad, cotejo_reserva, cotejo_reserva_<campo>, etc.

Recibir el webhook

Verifica la firma con el cuerpo crudo, antes de interpretarlo:

from flask import Flask, request
from verificar_curp import VerificarCurpError, parse_webhook

app = Flask(__name__)

@app.post("/webhooks/curp")
def curp_webhook():
    try:
        event = parse_webhook(
            os.environ["CURP_WEBHOOK_SECRET"],  # whsec_…
            request.get_data(),
            request.headers.get("X-Signature"),
            request.headers.get("X-Signature-Timestamp"),
        )
    except VerificarCurpError:
        return "", 400

    if event["event"] == "curp.verification.completed":
        print(event["idempotencyKey"], event["data"]["estatus"])
    return "", 200

verify_webhook_signature() hace lo mismo y devuelve True/False. Por defecto rechaza firmas con más de 300 s de antigüedad (tolerance_seconds). Eventos: curp.verification.completed, .failed, .retrying, .manual_review y extraction.completed (enlaces de captura).

Saldo

tokens = client.get_balance()

Errores

Todo fallo lanza VerificarCurpError, con code, status, block_reason y el cuerpo crudo en response:

from verificar_curp import VerificarCurpError

try:
    client.validate(curp)
except VerificarCurpError as err:
    if err.code == "INSUFFICIENT_TOKENS":
        ...  # recarga tokens en https://verificarcurp.com
code status cuándo
INVALID_REQUEST 400 Cuerpo inválido
DESTINATION_NOT_FOUND 400 El destino no existe o no es tuyo (no se cobra)
INVALID_PERSONA / INVALID_REFERENCE / INVALID_REQUESTER_NAME / INVALID_NAME 400 Campo inválido al crear un enlace
TOO_MANY_LIVE_LINKS 400 Ya tienes 20 enlaces vigentes
MISSING_API_KEY / INVALID_API_KEY 401 API key ausente o incorrecta
INSUFFICIENT_TOKENS 402 Sin saldo
NOT_FOUND 404 La verificación no es de tu cuenta
IDEMPOTENCY_KEY_REUSED 409 Misma idempotency_key con otra CURP
INTERNAL_ERROR 500 Error del servidor
NETWORK_ERROR / TIMEOUT — Del SDK
INVALID_INPUT / INVALID_SIGNATURE — Del SDK

Enlaces

MIT

Metadata

Release files for verificar-curp 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for verificar-curp 1.1.0
File Size Uploaded
verificar_curp-1.1.0.tar.gz 11.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for verificar-curp 1.1.0
File Interpreter ABI Platform
verificar_curp-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 23.2 kB

Release files / verificar_curp-1.1.0.tar.gz

Download URL verificar_curp-1.1.0.tar.gz
Size 11.4 kB
Tags Source
SHA-256 checksum
How to use checksums
bc9192c7fe701a5cc65ecfecf1906301f8afefe8e3d742a216c976d1dbbbc685
BLAKE2b-256 checksum
How to use checksums
cc6abaf2479ea2d221ca8b81b0e3bfb0ad7f4f97db5d69bff8ca25a62aba9725
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / verificar_curp-1.1.0-py3-none-any.whl

Download URL verificar_curp-1.1.0-py3-none-any.whl
Size 11.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
052776989be5a05a06439ca1a84e9ab7ea30ef3bf5620db467b621695d683eff
BLAKE2b-256 checksum
How to use checksums
2e54d047d57030f0849d70d7278fb1f7abbd70af3bfbca1bff3defc1847d254a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page