API de Certificados
Peça o certificado digital (e-CPF) do seu cliente à Innova Prime e receba cada mudança de etapa no seu sistema.
Visão geral
A integração tem duas partes:
POST assinado no seu endereço de webhook. Você também pode consultar quando quiser.Convenções: HTTPS obrigatório, JSON em UTF-8, datas em ISO 8601 com fuso de Brasília (-03:00), CPF só com dígitos e telefone no formato internacional.
Ambientes
Comece pelo ambiente de teste. A chave de produção é entregue depois que os seus testes forem aprovados.
| Ambiente | Endereço base | Observação |
|---|---|---|
| Teste | https://teste.innovaprimecertificados.com.br | Dados fictícios. Nenhuma mensagem sai para ninguém. |
| Produção | https://plataforma.innovaprimecertificados.com.br | Pedidos reais. |
Chave da API, segredo do webhook e endereço de webhook são diferentes em cada ambiente.
Autenticação
Toda chamada leva a sua chave no cabeçalho X-API-Key.
X-API-Key: ip_test_3Hq9...
- A chave é entregue pela Innova Prime, uma por parceiro e por ambiente. Chaves de teste começam com
ip_test_; de produção, comip_live_. - Cada chave enxerga somente os pedidos criados com ela. Pedidos de outros parceiros não existem para você.
- Guarde a chave no seu servidor, nunca no navegador ou em aplicativo instalado no celular.
- Suspeita de vazamento: peça uma chave nova. A antiga para de funcionar na hora.
Criar pedido
O corpo é multipart/form-data, com três partes:
| Parte | Tipo | Obrigatória | Conteúdo |
|---|---|---|---|
dados | texto (JSON) | Sim | Os campos da tabela abaixo |
documento | arquivo | Sim | Documento com foto do cliente (CNH ou RG): PDF, JPG ou PNG, até 15 MB |
certidao | arquivo | Não | Certidão complementar, mesmos formatos e limite |
Campos de dados:
| Campo | Tipo | Obrigatório | Regra |
|---|---|---|---|
referencia | texto, até 60 | Sim | Número da operação no seu sistema. Uma operação pode ter vários pedidos, um por cliente. Volta em todos os avisos. |
nome | texto, até 200 | Sim | Nome completo, como no documento |
cpf | 11 dígitos | Sim | Conferido pelo dígito verificador |
telefone | E.164 | Sim | Celular com código do país, ex.: +5519999990000 |
email | texto | Sim | E-mail do cliente |
observacoes | texto, até 500 | Não | Ex.: melhor horário para contato |
Exemplo de dados:
{
"referencia": "OP-2026-000123",
"nome": "Fulano de Tal",
"cpf": "52998224725",
"telefone": "+5519999990000",
"email": "fulano@exemplo.com",
"observacoes": "Prefere contato de manhã"
}
Resposta 201 Created:
{
"pedido_id": "c7f1e2a09b3d4e5f8a9b0c1d2e3f4a5b",
"referencia": "OP-2026-000123",
"nome": "Fulano de Tal",
"cpf": "52998224725",
"etapa": "CONTATO_INICIADO",
"criado_em": "2026-10-20T10:15:00-03:00"
}
Guarde o pedido_id: é ele que identifica o cliente em cada aviso.
CPF e telefone não se repetem
Enquanto um pedido seu estiver aberto (antes de INSTALADO, SEM_RETORNO ou CANCELADO):
- mesmo CPF de novo: nenhum pedido novo é criado. A resposta é
200 OKcom o pedido que já existe. Assim você pode reenviar com segurança quando não tiver certeza de que a primeira chamada chegou. - mesmo telefone com outro CPF: o pedido é recusado com
422, campotelefone.
Consultar pedido
Para quando um aviso não chegou, ou para conferir a situação:
Um pedido, com a etapa atual e o histórico.
Todos os pedidos daquela operação, um por cliente (lista; vazia se não houver nenhum).
Resposta 200 OK:
{
"pedido_id": "c7f1e2a09b3d4e5f8a9b0c1d2e3f4a5b",
"referencia": "OP-2026-000123",
"nome": "Fulano de Tal",
"cpf": "52998224725",
"etapa": "AGENDADO",
"agendado_para": "2026-10-21T14:00:00-03:00",
"criado_em": "2026-10-20T10:15:00-03:00",
"historico": [
{"etapa": "CONTATO_INICIADO", "ocorrido_em": "2026-10-20T10:15:00-03:00"},
{"etapa": "AGENDADO", "ocorrido_em": "2026-10-20T11:02:40-03:00"}
]
}
Um pedido_id que não foi criado com a sua chave responde 404, igual a um pedido que não existe.
Etapas do pedido
O campo etapa tem sempre um destes seis valores. A lista pode crescer em versões futuras: trate valor desconhecido sem erro.
etapa | Rótulo | Significado | Campo extra |
|---|---|---|---|
CONTATO_INICIADO | Contato iniciado | Pedido recebido; a Innova envia a mensagem de boas-vindas ao cliente | |
AGENDADO | Agendado | Videoconferência de validação marcada (ou remarcada) | agendado_para |
APROVADO | Aprovado | Validação aprovada | |
INSTALADO | Instalado | Certificado emitido e instalado | |
SEM_RETORNO | Sem retorno | O cliente não respondeu aos contatos | |
CANCELADO | Cancelado | Pedido encerrado sem emissão | motivo, quando houver |
INSTALADO, SEM_RETORNO e CANCELADO são finais na maior parte dos casos, mas um pedido SEM_RETORNO pode voltar para AGENDADO se o cliente responder depois.
Webhook de etapas
A cada mudança de etapa, a Innova faz POST no seu endereço de webhook, com o corpo em JSON e uma assinatura HMAC no cabeçalho.
Configuração
Informe à Innova um endereço HTTPS público por ambiente. A Innova devolve o segredo do webhook, usado só para conferir a assinatura. Ele não é a chave da API.
Corpo
{
"evento_id": "ev_9a1c0d7e5b2f4a6c8d0e",
"tipo": "certificado.etapa",
"pedido_id": "c7f1e2a09b3d4e5f8a9b0c1d2e3f4a5b",
"referencia": "OP-2026-000123",
"nome": "Fulano de Tal",
"cpf": "52998224725",
"etapa": "AGENDADO",
"etapa_rotulo": "Agendado",
"agendado_para": "2026-10-21T14:00:00-03:00",
"motivo": null,
"ocorrido_em": "2026-10-20T11:02:40-03:00"
}
O aviso traz pedido_id, referencia, nome e cpf, para identificar o cliente dentro da operação sem precisar consultar nada. Telefone e documentos não voltam: você já tem esses dados.
Cabeçalhos
| Cabeçalho | Conteúdo |
|---|---|
Content-Type | application/json |
X-Innova-Evento | Igual a evento_id |
X-Innova-Timestamp | Momento do envio, em segundos desde 1970 (Unix) |
X-Innova-Assinatura | sha256= + HMAC-SHA256 em hexadecimal de <timestamp>.<corpo exato>, com o segredo do webhook |
Conferir a assinatura
Calcule o HMAC sobre o corpo exatamente como chegou, antes de qualquer conversão de JSON, compare em tempo constante e recuse aviso com mais de 5 minutos.
import hashlib, hmac, time
def aviso_valido(corpo: bytes, timestamp: str, assinatura: str, segredo: str) -> bool:
if abs(time.time() - int(timestamp)) > 300:
return False
esperado = hmac.new(segredo.encode(), f"{timestamp}.".encode() + corpo,
hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={esperado}", assinatura)
const crypto = require("crypto");
function avisoValido(corpo, timestamp, assinatura, segredo) {
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const esperado = "sha256=" + crypto.createHmac("sha256", segredo)
.update(`${timestamp}.`).update(corpo).digest("hex");
const a = Buffer.from(esperado), b = Buffer.from(assinatura || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Resposta e reenvio
- Responda
2xxem até 10 segundos. Se o processamento for demorado, faça depois. - Sem
2xx, a Innova reenvia em 1, 5, 15 e 60 minutos e depois a cada hora, por até 24 horas. - O mesmo
evento_idpode chegar mais de uma vez: ignore o repetido. - Os avisos podem chegar fora de ordem: a etapa atual é a do maior
ocorrido_em, ou a da consulta do pedido. - Redirecionamentos (3xx) não são seguidos: informe o endereço final.
Erros e limites
Toda resposta de erro vem em JSON, com uma mensagem em português e, quando for o caso, o campo que causou o erro:
{"erro": "CPF inválido: confira os dígitos.", "campo": "cpf"}
| Código | Quando | O que fazer |
|---|---|---|
200 | Já existe pedido seu aberto para o mesmo CPF | Usar o pedido devolvido |
201 | Pedido criado | |
400 | Corpo fora do formato (JSON inválido, parte faltando) | Corrigir a requisição |
401 | Chave ausente ou inválida | Conferir X-API-Key e o ambiente |
404 | Pedido não encontrado | Conferir o pedido_id |
413 | Arquivo acima de 15 MB | Enviar arquivo menor |
415 | Formato de arquivo não aceito | Enviar PDF, JPG ou PNG |
422 | Campo inválido ou faltando, ou telefone já usado por outro CPF num pedido seu aberto | Ver campo e erro |
429 | Muitas chamadas seguidas | Esperar os segundos de Retry-After |
5xx | Falha da Innova | Tentar de novo depois; o pedido não duplica |
Limite: 60 chamadas por minuto por chave.
Teste rápido
No ambiente de teste, com a sua chave de teste:
curl -X POST https://teste.innovaprimecertificados.com.br/api/certificados/v1/pedidos \
-H "X-API-Key: $CHAVE_DE_TESTE" \
-F 'dados={"referencia":"TESTE-001","nome":"Fulano de Tal","cpf":"52998224725","telefone":"+5519999990000","email":"fulano@exemplo.com"}' \
-F "documento=@cnh-ficticia.jpg"
curl "https://teste.innovaprimecertificados.com.br/api/certificados/v1/pedidos?referencia=TESTE-001" \
-H "X-API-Key: $CHAVE_DE_TESTE"
Andar com o pedido pelas etapas (só no teste)
Para ver cada aviso chegando no seu webhook sem esperar ninguém, mova o seu pedido de teste:
curl -X POST https://teste.innovaprimecertificados.com.br/api/certificados/v1/teste/pedidos/$PEDIDO_ID/etapa \
-H "X-API-Key: $CHAVE_DE_TESTE" -H "Content-Type: application/json" \
-d '{"etapa": "AGENDADO"}'
# CANCELADO aceita um motivo:
# -d '{"etapa": "CANCELADO", "motivo": "Cliente desistiu"}'
Histórico de versões
| Versão | Data | Mudança |
|---|---|---|
| v1 | 12/10/2026 | Primeira versão: criar e consultar pedido, webhook de etapas, rota de teste |
Mudanças que quebram a integração só entram numa versão nova (/v2), avisada com antecedência. Campos e etapas novos podem aparecer na v1: ignore o que não conhecer.