Acompanhar o status da oferta em tempo real
Esse fluxo é destinado à integração do processo de Carta Oferta do R&S Gupy com sistemas externos da sua empresa permitindo receber notificações em tempo real sobre criação e mudanças de status da oferta.
A partir desse envio é possível acompanhar quando uma oferta é criada, enviada ao candidato, visualizada, aceita, recusada ou cancelada, e reagir a esses eventos no seu agente integrador.
Disponibilidade por planoA funcionalidade de Carta Oferta está incluída em todos os planos com acesso a API, com exceção dos planos Essential e Foundation. A liberação foi feita para 100% da base, exceto clientes nesses planos que não possuem a funcionalidade no plano contratado.
Esse fluxo utiliza webhookPara realizar integrações utilizando Webhooks é necessário um agente integrador (middleware) para receber e tratar os dados.
Para implementar integrações a partir de webhooks é necessário uma configuração prévia através da própria API Gupy: Veja aqui mais informações sobre o recebimento de webhooks
Atenção!A URL usada para receber o webhook DEVE ser um endereço HTTPS válido, exposto publicamente. Para configurar o webhook, consulte Webhook Configuração .
URLs com alta taxa de erro (100% dos erros nos últimos 7 dias) serão removidas sem aviso prévio.
O Webhook espera uma resposta em 30.000 ms. Caso a resposta não tenha ocorrido antes deste tempo, consideramos um timeout, consequentemente, um erro.
O sistema garante pelo menos uma entrega, então podem haver várias notificações do mesmo evento, use a propriedade id para identificar duplicatas.
Não há garantia de ordem de entrega, use a propriedade date para verificar qual evento aconteceu primeiro e classifique os eventos.
NÃO USE serviços como requestcatcher, eles podem expor dados.
É recomendado que o cliente informe em clientHeaders todos os headers que o endpoint de destino espera receber, incluindo o Content-Type correspondente ao seu formato de payload. Por exemplo, se o endpoint espera Content-Type: application/json, esse valor deve ser passado explicitamente em clientHeaders.
Gerando o token
Para utilizar este fluxo, é necessário utilizar o Bearer Token gerado nas configurações avançadas da plataforma. Acesse nossa seção de autenticação para saber como gerar o o token de autenticação.
No momento de gerar o token, habilite os endpoints necessários da V1:
Fluxo de integração
Configurar webhook: evento job-offer.status-changed
job-offer.status-changed- Acessar endpoint
POST /api/v1/webhooks - Ajustar o parâmetro
actionparajob-offer.status-changed - Inserir no
postbackUrlo endereço (URL segura) para onde será direcionado o webhook - Inserir o Bearer token e executar a requisição
Exemplo de requisição
curl --request POST \
--url https://api.gupy.io/api/v1/webhooks \
--header 'accept: application/json' \
--header 'authorization: Bearer XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
--header 'content-type: application/json' \
--data '
{
"action": "job-offer.status-changed",
"status": "active",
"postbackUrl": "https://urldo.agenteintegrador.net",
"techOwnerName": "Nome Sobrenome",
"techOwnerEmail": "[email protected]"
}
'Exemplo de resposta para um webhook cadastrado com sucesso
{
"id": "d5b2eca6-09c5-4014-9eb8-1d729dd2e3d6",
"action": "job-offer.status-changed",
"postbackUrl": "https://urldo.agenteintegrador.net",
"status": "active"
}Configurar webhook: evento job-offer.created
job-offer.created- Acessar endpoint
POST /api/v1/webhooks - Ajustar o parâmetro
actionparajob-offer.created - Inserir no
postbackUrlo endereço (URL segura) para onde será direcionado o webhook - Inserir o Bearer token e executar a requisição
Exemplo de requisição
curl --request POST \
--url https://api.gupy.io/api/v1/webhooks \
--header 'accept: application/json' \
--header 'authorization: Bearer XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' \
--header 'content-type: application/json' \
--data '
{
"action": "job-offer.created",
"status": "active",
"postbackUrl": "https://urldo.agenteintegrador.net",
"techOwnerName": "Nome Sobrenome",
"techOwnerEmail": "[email protected]"
}
'Exemplo de resposta para um webhook cadastrado com sucesso
{
"id": "d5b2eca6-09c5-4014-9eb8-1d729dd2e3d6",
"action": "job-offer.created",
"postbackUrl": "https://urldo.agenteintegrador.net",
"status": "active"
}Recebimento no agente integrador
Ciclo de vida da carta oferta
| Status | Descrição |
|---|---|
notSent | Criada, não enviada |
sent | Enviada ao candidato |
viewed | Visualizada pelo candidato |
accepted | Aceita |
rejected | Recusada (rejectReason obrigatório) |
canceled | Cancelada (manual ou ao enviar nova oferta) |
Evento job-offer.created
job-offer.createdO evento será disparado quando uma carta oferta for criada para uma candidatura. Por exemplo: quando um recrutador cria uma oferta com salário e dados de admissão para um candidato.
O payload inclui os dados da oferta, o usuário que a criou e os identificadores da candidatura e da vaga relacionadas.
Atenção!A transição para o status
notSentnão dispara o webhookjob-offer.status-changed. Para ser notificado da criação da oferta, configure o eventojob-offer.created.
O agente integrador receberá os dados do webhook conforme contrato JSON do evento job-offer.created.
Atenção!O exemplo abaixo trata-se de um webhook modelo e não é indicado trabalhar o desenvolvimento a partir do mesmo. O ideal é que o desenvolvimento seja a partir de um payload real.
Exemplo de payload — job-offer.created
job-offer.created{
"companyName": "Gupy Staging",
"event": "job-offer.created",
"id": "52528023-842b-4a54-a254-a5e558d562b0",
"date": "2026-07-15T17:19:34.135Z",
"data": {
"jobOffer": {
"id": 278167,
"sentAt": null,
"status": "notSent",
"createdAt": "2026-07-15T17:19:34.135Z",
"updatedAt": "2026-07-15T17:19:34.135Z",
"answeredAt": null,
"rejectReason": null,
"salaryAmount": 10000,
"admissionDate": "2026-07-15T03:00:00.000Z",
"admissionType": "employee_admission",
"salaryCurrency": "R$"
},
"user": {
"id": 48000,
"name": "User",
"email": "[email protected]",
"code": null
},
"application": {
"id": 2937132
},
"job": {
"id": 19139
}
}
}Evento job-offer.status-changed
job-offer.status-changedO evento será disparado quando o status de uma carta oferta mudar. Por exemplo: quando a oferta é enviada ao candidato, visualizada, aceita, recusada ou cancelada.
O payload inclui os dados atuais da oferta (com o status atualizado), os identificadores da candidatura e da vaga, e — quando aplicável — o usuário que realizou a ação. O campo user está presente nos status sent e canceled. Quando a oferta é recusada, rejectReason contém o motivo da recusa; quando é aceita ou recusada, answeredAt contém a data da resposta.
Condições de disparo por transição
| Transição | Observação |
|---|---|
→ notSent | Não dispara job-offer.status-changed — utilize job-offer.created |
→ sent | Portal Gupy |
→ viewed | Candidato abriu a carta no portal |
→ accepted / rejected | Resposta do candidato |
→ canceled | Cancelamento manual ou automático (nova oferta) |
Campos condicionais por status (jobOffer.status)
jobOffer.status)| Status | sentAt | answeredAt | rejectReason |
|---|---|---|---|
sent | preenchido | null | null |
viewed | preenchido | null | null |
accepted | preenchido | preenchido | null |
rejected | preenchido | preenchido | preenchido |
canceled | preenchido se já havia sido enviada; null se cancelada antes do envio | null | null |
Regra de cancelamentoO cancelamento manual só é permitido quando a oferta está em
sentouviewed. O cancelamento automático ocorre quando uma nova oferta é enviada (a oferta anterior já estava emsentouviewed).
O agente integrador receberá os dados do webhook conforme contrato JSON do evento job-offer.status-changed.
Atenção!O exemplo abaixo trata-se de um webhook modelo e não é indicado trabalhar o desenvolvimento a partir do mesmo. O ideal é que o desenvolvimento seja a partir de um payload real.
Exemplo de payload — transição para sent
sent{
"eventId": "880e8400-e29b-41d4-a716-446655440003",
"eventDate": "2026-06-20T10:00:00.000Z",
"action": "job-offer.status-changed",
"application": { "id": 12646330 },
"job": { "id": 8685731 },
"jobOffer": {
"id": 12345,
"status": "sent",
"createdAt": "2026-06-18T09:00:00.000Z",
"updatedAt": "2026-06-20T10:00:00.000Z",
"answeredAt": null,
"rejectReason": null,
"sentAt": "2026-06-20T10:00:00.000Z",
"salaryAmount": 8500.00,
"salaryCurrency": "BRL",
"admissionDate": "2026-07-01T00:00:00.000Z",
"admissionType": "employee_admission"
}
}Exemplo de payload — transição para viewed
viewed{
"eventId": "770e8400-e29b-41d4-a716-446655440002",
"eventDate": "2026-06-21T08:00:00.000Z",
"action": "job-offer.status-changed",
"application": { "id": 12646330 },
"job": { "id": 8685731 },
"jobOffer": {
"id": 12345,
"status": "viewed",
"createdAt": "2026-06-18T09:00:00.000Z",
"updatedAt": "2026-06-21T08:00:00.000Z",
"answeredAt": null,
"rejectReason": null,
"sentAt": "2026-06-20T10:00:00.000Z",
"salaryAmount": 8500.00,
"salaryCurrency": "BRL",
"admissionDate": "2026-07-01T00:00:00.000Z",
"admissionType": "employee_admission"
}
}Exemplo de payload — transição para accepted
accepted{
"eventId": "550e8400-e29b-41d4-a716-446655440000",
"eventDate": "2026-06-25T14:30:00.000Z",
"action": "job-offer.status-changed",
"application": { "id": 12646330 },
"job": { "id": 8685731 },
"jobOffer": {
"id": 12345,
"status": "accepted",
"createdAt": "2026-06-18T09:00:00.000Z",
"updatedAt": "2026-06-25T14:30:00.000Z",
"answeredAt": "2026-06-25T14:30:00.000Z",
"rejectReason": null,
"sentAt": "2026-06-20T10:00:00.000Z",
"salaryAmount": 8500.00,
"salaryCurrency": "BRL",
"admissionDate": "2026-07-01T00:00:00.000Z",
"admissionType": "employee_admission"
}
}Exemplo de payload — transição para rejected
rejected{
"eventId": "660e8400-e29b-41d4-a716-446655440001",
"eventDate": "2026-06-25T15:00:00.000Z",
"action": "job-offer.status-changed",
"application": { "id": 12646330 },
"job": { "id": 8685731 },
"jobOffer": {
"id": 12345,
"status": "rejected",
"createdAt": "2026-06-18T09:00:00.000Z",
"updatedAt": "2026-06-25T15:00:00.000Z",
"answeredAt": "2026-06-25T15:00:00.000Z",
"rejectReason": "O valor da oferta é menor do que mercado.",
"sentAt": "2026-06-20T10:00:00.000Z",
"salaryAmount": 8500.00,
"salaryCurrency": "BRL",
"admissionDate": "2026-07-01T00:00:00.000Z",
"admissionType": "employee_admission"
}
}Exemplo de payload — transição para canceled
canceled{
"eventId": "990e8400-e29b-41d4-a716-446655440004",
"eventDate": "2026-06-22T16:00:00.000Z",
"action": "job-offer.status-changed",
"application": { "id": 12646330 },
"job": { "id": 8685731 },
"jobOffer": {
"id": 12345,
"status": "canceled",
"createdAt": "2026-06-18T09:00:00.000Z",
"updatedAt": "2026-06-22T16:00:00.000Z",
"answeredAt": null,
"rejectReason": null,
"sentAt": "2026-06-20T10:00:00.000Z",
"salaryAmount": 8500.00,
"salaryCurrency": "BRL",
"admissionDate": "2026-07-01T00:00:00.000Z",
"admissionType": "employee_admission"
}
}Possíveis erros
Recebimento no agente integrador
O ambiente precisa estar público para poder receber os dados do webhook na postbackUrl, caso contrário ocorrerá falha na entrega.
Configuração incorreta do clientHeaders
Caso o clientHeaders seja customizado sem a inclusão do Content-Type esperado pelo endpoint, a requisição pode ser enviada sem esse header ou com um valor divergente do necessário, causando falha no processamento pelo destino.
Cadeia de certificados SSL ausente, expirada ou incompleta
Se o certificado SSL do ambiente de destino estiver ausente, expirado ou com a cadeia incompleta (faltando certificados intermediários), a conexão pode ser recusada durante o handshake TLS, resultando em falha na entrega dos dados.
Updated about 8 hours ago
