Notificacao via Callback

Muitas operacoes nas APIs da I-Systems sao assincronas. Quando voce cria um pedido (Serviceordering), agendamento (appointment) e Reparo (Troubleticket), o processamento pode levar alguns minutos. Para manter voce informado sobre mudancas de estado, enviamos notificacoes via webhook para um endpoint que voce configurar.

⚠️

Importante: Liberação de Firewall

Antes de utilizar as notificações via callback, você deve informar o endpoint (URL) do seu servidor para nossa equipe realizar a liberação no firewall. Sem essa liberação, nossos servidores não conseguirão enviar as notificações para o seu endpoint.

Como Funciona

1

Voce faz uma requisicao

Cria um Service Order, Appointment, etc.

2

API retorna resposta inicial

Voce recebe o recurso criado com estado inicial (ex: "acknowledged")

3

Processamento assincrono

Nossa plataforma processa a solicitacao em background

4

Notificacao via callback

Enviamos POST para seu endpoint com atualizacoes de estado

Configurando seu Endpoint de Callback

Requisitos do Endpoint

URL Publica e Acessivel

Seu endpoint deve estar acessivel pela internet via HTTPS

Suporte a HTTPS

Por seguranca, apenas endpoints HTTPS sao aceitos

Resposta Rapida

Retorne status 200-299 em ate 5 segundos

Idempotencia

Prepare-se para receber a mesma notificacao mais de uma vez

Como Configurar

O endpoint de callback e configurado por requisicao, no momento da criacao do recurso. Cada API que suporta callbacks tem um atributo especifico:

Atributos de Callback por API:
  • Service Order: callback no corpo da requisicao
  • Appointment: callback no corpo da requisicao
  • Trouble Ticket: callback no corpo da requisicao

Exemplos de Configuracao

Criando Service Order com Callback

Request

curl --location 'https://apim-isystems-uat-brzsth-001.ihstowers.com/serviceOrderingManagement/serviceOrder' \
--header 'x-service-provider: {{x-service-provider}}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng...' \
--data '{
    "externalId": "Integracao-Int24",
    "category": "SERVICE.ORDER",
    "serviceOrderItem": [
        {
            "id": "sfttp-1",
            "action": "create",
            "service": {
                "id": "1111111110",
                "serviceSpecification": {
                    "id": "CFS.FTTP.BASICO"
                },
                "serviceCharacteristic": [
                    {
                        "name": "serviceProfile",
                        "value": "ISYS_FTTP_400M"
                    },
                    {
                        "name": "addressId",
                        "value": "0001231512"
                    }
                ]
            }
        }
    ],
    "relatedParty": {
        "correlationId": "Integracao-Int24"
    }
}'

Response

{
    "id": "a96e34d7-fe6f-4306-b3bd-9616edb6314b9",
    "orderDate": "2025-10-23T17:16:43",
    "state": "Acknowledged"
}
Campos Importantes:
  • externalId: Identificador unico da sua aplicacao para rastrear o pedido
  • category: Categoria do pedido (SERVICE.ORDER)
  • action: Acao a ser executada (create, modify, delete)
  • serviceSpecification.id: ID da especificacao do servico (ex: CFS.FTTP.BASICO)
  • serviceProfile: Perfil de velocidade (ex: ISYS_FTTP_400M)
  • addressId: ID do endereco previamente qualificado
  • correlationId: ID de correlacao para rastreamento

Formato das Notificacoes

Estrutura da Notificacao

As notificacoes sao enviadas via HTTP POST para o endpoint configurado. O corpo da requisicao contem o recurso completo atualizado com seu novo estado.

Service Order State Change Notification

POST https://seu-sistema.com.br/api/webhooks/service-orders
Content-Type: application/json

{
  "id": "a96e34d7-fe6f-4306-b3bd-9616edb6314b9",
  "state": "Completed",
  "orderDate": "2025-10-23T17:26:50.4410000Z",
  "externalId": "Integracao-Int24",
  "details": [],
  "serviceOrderItem": [
    {
      "id": "sfttp-1",
      "action": "create",
      "service": {
        "id": "1111111110",
        "category": "CFS",
        "serviceSpecification": {
          "id": "CFS.FTTP.BASICO"
        },
        "serviceCharacteristic": [
          {
            "name": "serviceProfile",
            "value": "ISYS_FTTP_400M"
          },
          {
            "name": "addressId",
            "value": "0001231512"
          }
        ]
      }
    }
  ],
  "relatedParty": {}
}
Estados Possiveis do Service Order:
  • Acknowledged: Pedido recebido e em fila para processamento
  • InProgress: Pedido em processamento
  • Completed: Pedido concluido com sucesso
  • Failed: Pedido falhou durante o processamento
  • Cancelled: Pedido cancelado

Appointment State Change Notification

POST https://seu-sistema.com.br/api/webhooks/appointments
Content-Type: application/json

{
  "id": "006",
  "name": "ACTIVITY_CREATED",
  "timeOcurred": "2023-01-23T06:58:10Z",
  "event": {
    "appointment": {
      "serviceAppointmentId": "SA-562403",
      "workOrderId": "00001192",
      "status": "Atribuído",
      "category": "Instalacao BL",
      "serviceType": "FTTH",
      "relatedParty": [
        {
          "id": "roberto.silva@email.com",
          "name": "Roberto da Silva",
          "role": "technician"
        },
        {
          "id": "6deea995-05bc-49d7-b990-4bdf443fb80e4098",
          "role": "orderId"
        }
      ],
      "customer": {
        "name": "Eduardo Franco",
        "serviceId": "TEN|353573730",
        "contactMedium": [
          {
            "characteristic": {
              "phoneNumber": "21965874562"
            }
          }
        ]
      },
      "validFor": {
        "startDateTime": "2023-01-23T06:58:10Z",
        "endDateTime": "2023-01-23T06:58:10Z"
      }
    }
  }
}
Campos Importantes do Appointment:
  • name: Tipo do evento (ACTIVITY_CREATED, ACTIVITY_UPDATED, etc.)
  • serviceAppointmentId: ID do agendamento
  • workOrderId: ID da ordem de servico associada
  • status: Estado atual (Atribuído, Em Andamento, Concluído, etc.)
  • category: Categoria da atividade (Instalacao BL, Reparo, etc.)
  • serviceType: Tipo de servico (FTTH, FTTP, FTTO)
  • relatedParty: Tecnico e ID do pedido relacionado
  • customer: Informacoes do cliente final
  • validFor: Janela de agendamento

Trouble Ticket State Change Notification

POST https://seu-sistema.com.br/api/webhooks/tickets
Content-Type: application/json

{
  "id": "TT_00000183-2022",
  "creationDate": "2022-12-29T10:00:27Z",
  "description": "Correcao.",
  "category": "Corrective",
  "expectedResolutionDate": "2022-12-29T10:00:27Z",
  "resolutionDate": "2022-12-29T10:00:27Z",
  "status": "Resolved",
  "correctAddress": "Endereço novo",
  "relatedParty": [
    {
      "role": "Corrective",
      "lastComment": "Ultimo Comentario"
    }
  ],
  "propertiesForm": [
    {
      "name": "Motivo nao validacao",
      "value": "Velocidade não atingida"
    },
    {
      "name": "Responsavel certificacao",
      "value": "COP"
    },
    {
      "name": "Status validacao cert",
      "value": "Ok"
    }
  ]
}
Campos Importantes do Trouble Ticket:
  • id: ID unico do ticket (ex: TT_00000183-2022)
  • status: Estado atual (Resolved, InProgress, Pending, etc.)
  • category: Categoria do ticket (Corrective, Preventive, etc.)
  • description: Descricao do problema
  • creationDate: Data de criacao do ticket
  • expectedResolutionDate: Data esperada de resolucao
  • resolutionDate: Data efetiva da resolucao
  • correctAddress: Endereco corrigido (se aplicavel)
  • relatedParty: Informacoes sobre responsaveis e comentarios
  • propertiesForm: Campos customizados com informacoes adicionais

Implementando o Endpoint de Callback

Exemplo de Implementacao

Node.js (Express)

const express = require('express');
const app = express();

app.use(express.json());

// Endpoint para receber notificacoes de Service Orders
app.post('/api/webhooks/service-orders', async (req, res) => {
  try {
    const serviceOrder = req.body;

    // Log da notificacao recebida
    console.log('Notificacao recebida:', {
      id: serviceOrder.id,
      externalId: serviceOrder.externalId,
      state: serviceOrder.state,
      orderDate: serviceOrder.orderDate
    });

    // Processar a notificacao de forma assincrona
    processServiceOrderNotification(serviceOrder)
      .catch(err => console.error('Erro ao processar notificacao:', err));

    // Retornar resposta rapida (nao esperar processamento)
    res.status(200).json({ received: true });

  } catch (error) {
    console.error('Erro ao receber notificacao:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

async function processServiceOrderNotification(serviceOrder) {
  // Verificar idempotencia (evitar processar duplicatas)
  const alreadyProcessed = await checkIfEventProcessed(serviceOrder.id);
  if (alreadyProcessed) {
    console.log('Pedido ja processado:', serviceOrder.id);
    return;
  }

  // Salvar que este pedido foi processado
  await markEventAsProcessed(serviceOrder.id);

  // Atualizar seu sistema baseado no novo estado
  switch (serviceOrder.state) {
    case 'Acknowledged':
      await updateOrderStatus(serviceOrder.externalId, 'RECEBIDO');
      await notifyCustomer(serviceOrder.externalId, 'Seu pedido foi recebido');
      break;

    case 'InProgress':
      await updateOrderStatus(serviceOrder.externalId, 'EM_ANDAMENTO');
      await notifyCustomer(serviceOrder.externalId, 'Seu pedido esta em andamento');
      break;

    case 'Completed':
      await updateOrderStatus(serviceOrder.externalId, 'CONCLUIDO');
      await notifyCustomer(serviceOrder.externalId, 'Seu pedido foi concluido');
      break;

    case 'Failed':
      await updateOrderStatus(serviceOrder.externalId, 'FALHOU');
      await notifyCustomer(serviceOrder.externalId, 'Houve um problema com seu pedido');
      break;

    case 'Cancelled':
      await updateOrderStatus(serviceOrder.externalId, 'CANCELADO');
      await notifyCustomer(serviceOrder.externalId, 'Seu pedido foi cancelado');
      break;

    default:
      console.log('Estado desconhecido:', serviceOrder.state);
  }
}

// Funcoes auxiliares (implementar conforme sua necessidade)
async function checkIfEventProcessed(orderId) {
  // Verificar no banco de dados se este orderId ja foi processado
  // Retorna true se ja foi processado, false caso contrario
}

async function markEventAsProcessed(orderId) {
  // Salvar no banco de dados que este pedido foi processado
  // Incluir timestamp para auditoria
}

async function updateOrderStatus(externalId, status) {
  // Atualizar status do pedido no seu sistema
}

async function notifyCustomer(externalId, message) {
  // Enviar notificacao para o cliente (email, SMS, push, etc)
}

app.listen(3000, () => {
  console.log('Servidor rodando na porta 3000');
});

Python (Flask)

from flask import Flask, request, jsonify
import logging
from datetime import datetime

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

@app.route('/api/webhooks/service-orders', methods=['POST'])
def service_order_webhook():
    try:
        service_order = request.get_json()

        # Log da notificacao
        logging.info(f"Notificacao recebida: {service_order.get('id')}")

        # Processar de forma assincrona
        process_service_order_notification(service_order)

        # Retornar resposta rapida
        return jsonify({"received": True}), 200

    except Exception as e:
        logging.error(f"Erro ao processar webhook: {str(e)}")
        return jsonify({"error": "Internal server error"}), 500


def process_service_order_notification(service_order):
    order_id = service_order.get('id')
    external_id = service_order.get('externalId')
    state = service_order.get('state')

    # Verificar idempotencia
    if check_if_event_processed(order_id):
        logging.info(f"Pedido ja processado: {order_id}")
        return

    # Marcar como processado
    mark_event_as_processed(order_id)

    # Processar baseado no estado
    if state == 'Acknowledged':
        update_order_status(external_id, 'RECEBIDO')
        notify_customer(external_id, 'Seu pedido foi recebido')

    elif state == 'InProgress':
        update_order_status(external_id, 'EM_ANDAMENTO')
        notify_customer(external_id, 'Seu pedido esta em andamento')

    elif state == 'Completed':
        update_order_status(external_id, 'CONCLUIDO')
        notify_customer(external_id, 'Seu pedido foi concluido')

    elif state == 'Failed':
        update_order_status(external_id, 'FALHOU')
        notify_customer(external_id, 'Houve um problema')

    elif state == 'Cancelled':
        update_order_status(external_id, 'CANCELADO')
        notify_customer(external_id, 'Seu pedido foi cancelado')


def check_if_event_processed(order_id):
    # Implementar verificacao no banco de dados
    pass

def mark_event_as_processed(order_id):
    # Implementar gravacao no banco de dados
    pass

def update_order_status(external_id, status):
    # Implementar atualizacao de status
    pass

def notify_customer(external_id, message):
    # Implementar notificacao ao cliente
    pass


if __name__ == '__main__':
    app.run(port=3000)

Boas Praticas

Responda Rapidamente

Retorne HTTP 200-299 imediatamente. Processe a notificacao de forma assincrona apos retornar a resposta.

Implemente Idempotencia

Use o campo id do pedido para detectar e ignorar notificacoes duplicadas. Armazene IDs de pedidos ja processados com seus estados.

Valide a Origem

Considere implementar validacao de origem (IP whitelist, assinatura HMAC) para garantir que callbacks vem da I-Systems.

Trate Erros Graciosamente

Se seu endpoint falhar, iremos tentar reenviar a notificacao. Implemente logs detalhados para debugging.

Use Filas

Para alto volume, considere usar filas de mensagens (SQS, RabbitMQ) para processar callbacks de forma confiavel.

Monitore seu Endpoint

Configure alertas para monitorar disponibilidade e tempo de resposta do seu endpoint de callback.

Politica de Retry

Se seu endpoint falhar ao receber uma notificacao, tentaremos reenviar ate 3 vezes

Cenarios de Retry

  • Falhas gerais: Ate 3 tentativas de notificacao
  • Erros de autenticacao (401/403/440): Ate 6 tentativas (com renovacao de token)
  • Erros 400/412: Sem retry (descartado imediatamente)

Importante: Apos esgotar as tentativas, a notificacao e descartada. Voce pode consultar o estado atual do recurso via API a qualquer momento.