Webhooks
Webhooks permitem receber notificações em tempo real sobre eventos da plataforma. A MediQuo pode configurar as inscrições diretamente para o parceiro. Se preferir, utilize os endpoints abaixo para gerenciar as inscrições de forma autônoma.
Eventos Disponíveis
| Evento |
Descrição |
LICENCE_CREATED_SUCCESS |
Licença criada e processada com sucesso |
LICENCE_CREATED_FAILED |
Falha na criação ou processamento da licença |
GET /webhooks/subscriptions
Retorna a lista paginada de inscrições.
Parâmetros da Query
| Nome |
Tipo |
Obrigatório |
Descrição |
| page |
integer |
não |
Número da página (padrão: 0) |
| size |
integer |
não |
Itens por página (padrão: 20) |
| sort |
string |
não |
Ordenação (ex: name,asc) |
| index |
string |
não |
Filtro de busca por nome |
Cabeçalhos
| Header |
Valor |
Authorization |
Bearer {token} |
Accept |
application/hal+json |
Exemplo de Requisição
Bashcurl -X GET "https://api-portal.mediquo.com.br/webhooks/subscriptions?page=0&size=20" \
-H "Authorization: Bearer {seu_token}" \
-H "Accept: application/hal+json"
Respostas
| Código |
Descrição |
| 200 |
Lista paginada de inscrições |
| 401 |
Token inválido ou expirado |
| 403 |
Sem permissão |
GET /webhooks/subscriptions/active
Retorna a lista paginada de inscrições filtrada pelo status ativo.
Parâmetros da Query
| Nome |
Tipo |
Obrigatório |
Descrição |
| active |
boolean |
não |
Filtro por status ativo/inativo |
| page |
integer |
não |
Número da página (padrão: 0) |
| size |
integer |
não |
Itens por página (padrão: 20) |
Cabeçalhos
| Header |
Valor |
Authorization |
Bearer {token} |
Accept |
application/hal+json |
Exemplo de Requisição
Bashcurl -X GET "https://api-portal.mediquo.com.br/webhooks/subscriptions/active?active=true&page=0&size=20" \
-H "Authorization: Bearer {seu_token}" \
-H "Accept: application/hal+json"
Respostas
| Código |
Descrição |
| 200 |
Lista paginada de inscrições filtrada |
| 401 |
Token inválido ou expirado |
| 403 |
Sem permissão |
GET /webhooks/subscriptions/{id}
Retorna os dados de uma inscrição específica.
Parâmetros do Path
| Nome |
Tipo |
Obrigatório |
Descrição |
| id |
integer |
sim |
ID da inscrição |
Cabeçalhos
| Header |
Valor |
Authorization |
Bearer {token} |
Accept |
application/hal+json |
Exemplo de Requisição
Bashcurl -X GET https://api-portal.mediquo.com.br/webhooks/subscriptions/1 \
-H "Authorization: Bearer {seu_token}" \
-H "Accept: application/hal+json"
Resposta de Sucesso: 200 OK
JSON{
"id": 1,
"tenant": "partner-tenant",
"active": true,
"name": "Minha Integração",
"url": "https://meu-dominio.com/webhook/licencas",
"description": "Receber eventos de licenças",
"events": ["LICENCE_CREATED_SUCCESS", "LICENCE_CREATED_FAILED"],
"createdAt": "2025-01-27T10:00:00.000Z",
"updatedAt": "2025-01-27T10:00:00.000Z"
}
Respostas de Erro
| Código |
Descrição |
| 401 |
Token inválido ou expirado |
| 403 |
Sem permissão |
| 404 |
Inscrição não encontrada |
POST /webhooks/subscriptions
Cria uma nova inscrição de webhook.
Cabeçalhos
| Header |
Valor |
Authorization |
Bearer {token} |
Content-Type |
application/json |
Accept |
application/hal+json |
Corpo da Requisição
| Campo |
Tipo |
Obrigatório |
Descrição |
| name |
string |
sim |
Nome identificador da inscrição |
| url |
string |
sim |
URL HTTPS do endpoint receptor |
| events |
array |
sim |
Lista de eventos para inscrição |
| description |
string |
não |
Descrição opcional |
| active |
boolean |
não |
Status da inscrição (padrão: true) |
| headerName |
string |
não |
Nome do header customizado enviado em cada entrega |
| headerValue |
string |
não |
Valor do header customizado |
Os campos headerName e headerValue permitem configurar um header de autenticação que será incluído em todas as requisições enviadas ao seu endpoint (ex: X-Webhook-Secret).
A URL do endpoint receptor deve obrigatoriamente usar protocolo HTTPS.
Exemplo de Requisição
Bashcurl -X POST https://api-portal.mediquo.com.br/webhooks/subscriptions \
-H "Authorization: Bearer {seu_token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Minha Integração",
"url": "https://meu-dominio.com/webhook/licencas",
"description": "Receber eventos de licenças",
"events": ["LICENCE_CREATED_SUCCESS", "LICENCE_CREATED_FAILED"],
"active": true,
"headerName": "X-Webhook-Secret",
"headerValue": "meu-segredo"
}'
Resposta de Sucesso: 200 OK
Retorna o objeto da inscrição criada com seu id.
Respostas de Erro
| Código |
Descrição |
| 400 |
Campos obrigatórios ausentes ou inválidos |
| 401 |
Token inválido ou expirado |
| 403 |
Sem permissão |
PUT /webhooks/subscriptions/{id}
Atualiza os dados de uma inscrição.
Parâmetros do Path
| Nome |
Tipo |
Obrigatório |
Descrição |
| id |
integer |
sim |
ID da inscrição |
Cabeçalhos
| Header |
Valor |
Authorization |
Bearer {token} |
Content-Type |
application/json |
Accept |
application/hal+json |
Corpo da Requisição
| Campo |
Tipo |
Obrigatório |
Descrição |
| name |
string |
sim |
Nome identificador da inscrição |
| url |
string |
sim |
URL HTTPS do endpoint receptor |
| events |
array |
sim |
Lista de eventos para inscrição |
| description |
string |
não |
Descrição opcional |
| active |
boolean |
não |
Status da inscrição |
| headerName |
string |
não |
Nome do header customizado |
| headerValue |
string |
não |
Valor do header customizado |
Exemplo de Requisição
Bashcurl -X PUT https://api-portal.mediquo.com.br/webhooks/subscriptions/1 \
-H "Authorization: Bearer {seu_token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Minha Integração Atualizada",
"url": "https://meu-dominio.com/webhook/licencas",
"events": ["LICENCE_CREATED_SUCCESS"]
}'
Respostas
| Código |
Descrição |
| 200 |
Inscrição atualizada. Retorna o objeto completo |
| 400 |
Requisição inválida |
| 401 |
Token inválido ou expirado |
| 403 |
Sem permissão |
| 404 |
Inscrição não encontrada |
DELETE /webhooks/subscriptions/{id}
Remove uma inscrição de webhook.
Parâmetros do Path
| Nome |
Tipo |
Obrigatório |
Descrição |
| id |
integer |
sim |
ID da inscrição |
Cabeçalhos
| Header |
Valor |
Authorization |
Bearer {token} |
Accept |
application/hal+json |
Exemplo de Requisição
Bashcurl -X DELETE https://api-portal.mediquo.com.br/webhooks/subscriptions/1 \
-H "Authorization: Bearer {seu_token}"
Respostas
| Código |
Descrição |
| 200 |
Inscrição removida |
| 401 |
Token inválido ou expirado |
| 403 |
Sem permissão |
| 404 |
Inscrição não encontrada |
GET /webhooks/subscriptions/{id}/deliveries
Retorna o histórico de entregas de uma inscrição.
Parâmetros do Path
| Nome |
Tipo |
Obrigatório |
Descrição |
| id |
integer |
sim |
ID da inscrição |
Parâmetros da Query
| Nome |
Tipo |
Obrigatório |
Descrição |
| page |
integer |
não |
Número da página (padrão: 0) |
| size |
integer |
não |
Itens por página (padrão: 20) |
Cabeçalhos
| Header |
Valor |
Authorization |
Bearer {token} |
Accept |
application/hal+json |
Exemplo de Requisição
Bashcurl -X GET "https://api-portal.mediquo.com.br/webhooks/subscriptions/1/deliveries?page=0&size=20" \
-H "Authorization: Bearer {seu_token}" \
-H "Accept: application/hal+json"
Resposta de Sucesso: 200 OK
JSON{
"totalPages": 1,
"totalElements": 2,
"content": [
{
"id": 1,
"subscriptionId": 1,
"subscriptionName": "Minha Integração",
"eventType": "LICENCE_CREATED_SUCCESS",
"status": "SUCCESS",
"httpStatusCode": 200,
"errorMessage": null,
"sentAt": "2025-01-27T10:00:00.000Z",
"createdAt": "2025-01-27T10:00:00.000Z"
}
]
}
Campos do Histórico
| Campo |
Tipo |
Descrição |
subscriptionId |
integer |
ID da inscrição |
subscriptionName |
string |
Nome da inscrição |
eventType |
string |
Tipo do evento entregue |
status |
string |
SUCCESS ou FAILED |
httpStatusCode |
integer |
Código HTTP retornado pelo seu endpoint |
errorMessage |
string |
Mensagem de erro (quando FAILED) |
sentAt |
string |
Data/hora do envio |
Respostas de Erro
| Código |
Descrição |
| 401 |
Token inválido ou expirado |
| 403 |
Sem permissão |
| 404 |
Inscrição não encontrada |
O sistema envia uma requisição POST com Content-Type: application/json para a URL configurada em cada evento.
Payload: LICENCE_CREATED_SUCCESS
JSON{
"eventType": "LICENCE_CREATED_SUCCESS",
"timestamp": "2025-01-15T10:30:00.000Z",
"tenant": "partner-tenant-id",
"licence": {
"code": "LIC-2025-001",
"clientId": 1,
"planId": 1,
"name": "Maria Silva",
"email": "maria@email.com",
"phoneNumber": "11999999999",
"status": "CREATED",
"maxRedemptions": 10,
"pricing": 49.90
},
"error": null
}
Payload: LICENCE_CREATED_FAILED
JSON{
"eventType": "LICENCE_CREATED_FAILED",
"timestamp": "2025-01-15T10:30:00.000Z",
"tenant": "partner-tenant-id",
"licence": null,
"error": {
"message": "Client not found for tenant",
"type": "ResourceNotFoundException"
}
}
Requerimentos do Endpoint Receptor
Seu endpoint webhook deve:
- Aceitar requisições HTTP POST com
Content-Type: application/json
- Responder com código 2xx para confirmar o recebimento
- Responder em até 30 segundos. Entregas que ultrapassem esse limite são marcadas como
FAILED
- Ser idempotente. O mesmo evento pode ser entregue mais de uma vez; use a combinação de
eventType + timestamp + licence.code para detectar duplicatas
- Usar HTTPS obrigatoriamente
O sistema não reenvia automaticamente entregas com falha. Monitore o histórico via GET /webhooks/subscriptions/{id}/deliveries e acione reenvios manualmente se necessário.
Garantias de Entrega
Política de Retry
O sistema não reenvia automaticamente entregas que falharam caso seu endpoint retorne código não 2xx, ultrapasse o tempo limite ou esteja inacessível. A entrega é marcada como FAILED no histórico.
Ordem de Entrega
Webhooks são entregues de forma assíncrona. A ordem das entregas não é garantida, especialmente em momentos de alta carga.
Idempotência
Seu endpoint deve tratar eventos duplicados de forma idempotente. Use a combinação de eventType + timestamp + licence.code (para eventos de sucesso) para detectar e ignorar duplicatas.
Considerações de Segurança
HTTPS Obrigatório
Seu endpoint de webhook deve usar HTTPS para garantir a transmissão segura dos dados.
Whitelist de IPs
A lista de endereços IP de onde as requisições de webhook serão originadas é fornecida durante o processo de integração.
Validação da Requisição
Sempre valide as requisições de webhook recebidas:
- Verifique se a estrutura da requisição corresponde ao payload esperado
- Valide se o
tenant informado corresponde ao(s) tenant(s) esperados
- Verifique o
timestamp para prevenir ataques de replay
- Use
headerName / headerValue para autenticar entregas no seu endpoint
Exemplos de Implementação
Node.js / Express
JavaScriptapp.post('/webhook/licence-events', (req, res) => {
const { eventType, timestamp, tenant, licence, error } = req.body;
if (eventType === 'LICENCE_CREATED_SUCCESS') {
console.log(`Licença ${licence.code} criada com sucesso`);
} else if (eventType === 'LICENCE_CREATED_FAILED') {
console.log(`Falha na criação: ${error.message}`);
}
res.status(200).json({ received: true });
});
Python / Flask
Python@app.route('/webhook/licence-events', methods=['POST'])
def handle_webhook():
data = request.json
event_type = data['eventType']
if event_type == 'LICENCE_CREATED_SUCCESS':
print(f"Licença {data['licence']['code']} criada com sucesso")
elif event_type == 'LICENCE_CREATED_FAILED':
print(f"Falha na criação: {data['error']['message']}")
return jsonify({'received': True}), 200
Java / Spring Boot
Java@PostMapping("/webhook/licence-events")
public ResponseEntity<Map<String, Boolean>> handleWebhook(@RequestBody WebhookPayloadDTO payload) {
if (payload.getEventType() == WebhookEventType.LICENCE_CREATED_SUCCESS) {
logger.info("Licença {} criada com sucesso", payload.getLicence().getCode());
} else if (payload.getEventType() == WebhookEventType.LICENCE_CREATED_FAILED) {
logger.error("Falha na criação: {}", payload.getError().getMessage());
}
return ResponseEntity.ok(Map.of("received", true));
}
Monitoramento e Problemas Comuns
Webhook não recebido
- Verifique se a inscrição está
active: true
- Confirme que os tipos de evento corretos estão inscritos
- Garanta que seu endpoint esteja acessível a partir dos nossos servidores
- Revise regras de firewall e configuração de rede
Entrega marcada como FAILED
- Verifique os logs do seu endpoint em busca de erros
- Confirme que seu endpoint retorna código 2xx
- Garanta que o tempo de resposta esteja abaixo de 30 segundos
- Verifique o campo
errorMessage no histórico de entregas
Recebimento de eventos duplicados
Esse comportamento é esperado. Implemente processamento idempotente usando licence.code + timestamp para detectar duplicatas.
Boas Práticas
- Responda rapidamente: Confirme o recebimento imediatamente (200 OK) e processe em segundo plano de forma assíncrona.
- Registre tudo: Registre todos os webhooks recebidos para auditoria e depuração.
- Trate falhas de forma resiliente: Seu sistema deve continuar operando mesmo se o processamento de webhooks falhar.
- Monitore o status de entrega: Verifique regularmente o histórico de entregas para identificar problemas cedo.
- Use filas: Considere usar uma fila de mensagens para processar webhooks de forma assíncrona.