Endpoints
`webhooks.list`, `list_all`, `iterate`, `get`, `create`, `update`, `delete`, `rotate_secret`, `test`, `get_delivery` e `replay_delivery`, e os registos de entregas e de atividade.
Todos os métodos
endpoint = client.webhooks.create( url: "https://acme.com/hooks/mail", eventTypes: ["email.sent", "email.bounced"], description: "Billing service") File.write(".openemail-webhook-secret", endpoint[:secret]) client.webhooks.listclient.webhooks.get(endpoint[:id])client.webhooks.update(endpoint[:id], enabled: false)client.webhooks.test(endpoint[:id])latest = client.webhooks.list_deliveries(endpoint[:id], limit: 1).items.firstclient.webhooks.get_delivery(endpoint[:id], latest[:id])client.webhooks.replay_delivery(endpoint[:id], latest[:id])rotated = client.webhooks.rotate_secret(endpoint[:id])File.write(".openemail-webhook-secret", rotated[:secret])client.webhooks.delete(endpoint[:id])create é a ÚNICA altura em que o segredo é devolvido, além de rotate_secret. Uma leitura nunca o repete, por isso guarde-o antes de fazer mais alguma coisa. Omita eventTypes para o conjunto por omissão, todos os eventos email.* exceto email.replied. email.replied, domain.*, suppression.*, file.* e form.* só chegam a um endpoint quando este os nomeia.
rotate_secret não tem janela de sobreposição. O segredo antigo deixa de funcionar imediatamente, por isso coloque o novo em produção antes de rodar. Nunca é repetido automaticamente: uma repetição rodaria uma segunda vez e invalidaria o segredo que a primeira tentativa devolveu.
create também não é repetido, por isso uma falha de rede pode deixar um endpoint criado com um segredo que nunca viu. Verifique list antes de o criar de novo. Um espaço de trabalho comporta 10 endpoints por omissão, e o seguinte acima do limite dá um 422 workspace_limit_reached.
A que pode subscrever
OpenEmail::WEBHOOK_EVENTS é um Hash congelado com o nome de cada evento, para que possa apresentar a lista sem fazer um pedido, e webhooks.list_events devolve os mesmos nomes com uma frase para cada um, mais os limites a que um endpoint está sujeito. Os eventos são eventos da **caixa de correio**, não desta API: email.received dispara para o correio que chega à aplicação, e email.sent dispara para uma mensagem enviada pelo editor de mensagens. Subscrever não é o mesmo que observar o seu próprio tráfego de API.
file.uploaded dispara quando um ficheiro é colocado na página Ficheiros, e file.deleted quando um é eliminado. O seu data contém fileId, filename, mimeType, sizeBytes, direction, to, threadId, messageId, e uploadedAt ou deletedAt. to é o endereço a que o ficheiro pertence, ou nil para um ficheiro que pertence a todo o espaço de trabalho.
Os eventos de ficheiros não estão no conjunto por omissão, por isso um endpoint só os recebe quando os nomeia em eventTypes. Um endpoint limitado a alguns endereços só é avisado sobre os ficheiros desses endereços, pelo que um ficheiro carregado para todo o espaço de trabalho, com to a nil, não lhe é enviado.
form.submitted dispara quando alguém se inscreve através de um dos seus formulários, e form.confirmed quando uma inscrição pendente entra nas audiências, porque a pessoa abriu a ligação de confirmação ou porque a inscrição foi aprovada por si. O data de form.submitted contém formId, formName, submissionId, email, status, answers, audienceIds, sourceUrl e submittedAt. O data de form.confirmed contém formId, formName, submissionId, email, audienceIds, via, que é link ou approval, e confirmedAt.
Uma inscrição num formulário sem dupla confirmação envia form.submitted com status added e nenhum form.confirmed, por isso trate esse par como o momento em que alguém entra. Quem se inscreve de novo antes de confirmar mantém o mesmo submissionId, e form.submitted só volta a ser enviado quando as respostas mudaram. Os eventos de formulário não estão no conjunto por omissão, e um endpoint limitado a alguns endereços nunca os recebe, porque as inscrições pertencem a todo o espaço de trabalho.
Provar que funciona
result = client.webhooks.test("whe_3f9c2a7b1e4d8f60a5c7b92d")puts result.dig(:delivery, :status), result.dig(:delivery, :responseCode) client.webhooks.iterate_deliveries("whe_3f9c2a7b1e4d8f60a5c7b92d") do |delivery| puts "#{delivery[:eventType]} #{delivery[:status]} #{delivery[:responseCode]} #{delivery[:error]}"endtest envia por POST um evento email.sent sintético e assinado e espera que a tentativa termine. Retorna normalmente seja qual for a resposta do seu recetor, por isso baseie a lógica em delivery[:status] e não no facto de a chamada ter lançado uma exceção. Um 4xx é uma resposta útil: o URL está acessível e a recusa veio do seu próprio handler, muitas vezes da verificação da assinatura.
Um responseCode a nil significa que não houve resposta nenhuma (DNS, TLS, um timeout), o que é um facto diferente de uma resposta que disse 0. Cada linha leva attempt e maxAttempts, por isso várias linhas podem descrever um só evento: o mesmo eventId entre elas é o evento, e o número da tentativa é a tentativa. nextAttemptAt indica quando está prevista a repetição automática que se segue a uma linha.
Enviar de novo
detail = client.webhooks.get_delivery("whe_3f9c2a7b1e4d8f60a5c7b92d", "whd_8c1e4a7f2b9d3e6a0c5f1b28")p detail[:payload], detail[:responseBody], detail[:replayRefusal] replay = client.webhooks.replay_delivery("whe_3f9c2a7b1e4d8f60a5c7b92d", "whd_8c1e4a7f2b9d3e6a0c5f1b28")p replay.dig(:delivery, :status), replay.dig(:delivery, :responseCode)Uma entrega que continua a falhar é tentada até 8 vezes: no momento, depois ao fim de 1 minuto, 5 minutos, 30 minutos, 2 horas, 5 horas, 10 horas e 10 horas, cerca de 27 horas e meia no total. Só se repete uma falha que valha a pena repetir: sem resposta, 408, 425, 429 ou um 5xx. Um reenvio manda outra vez o evento guardado com o mesmo id, type, createdAt e data, pelo que um recetor que descarta ids já tratados o trata como o evento que já conhece. Só a assinatura é nova.
replay_deliveryenvia um evento agora e devolve o que o seu servidor respondeu. Funciona também numa tentativa entregue e nunca é repetido. Antes de enviar, as repetições automáticas desse evento que ainda não começaram ficam em pausa: continuam canceladas se o reenvio for entregue e retomam no seu horário se falhar.- Se nesse momento estiver a ser enviada uma repetição automática do mesmo evento,
replay_deliverynão envia nada e lança um 409retry_in_progress, e enquanto outro reenvio dele ainda estiver a ser enviado lança um 409replay_in_progress, para que o seu recetor nunca receba duas cópias ao mesmo tempo, nem de dois reenvios feitos no mesmo instante. Espere alguns segundos e leiaget_delivery, porque essa repetição ou esse reenvio pode entregá-lo. O reenvio é um evento de cada vez: nenhuma chamada reenvia todas as entregas falhadas. - Também lança um 409 para um endpoint desligado (
webhook_disabled), um evento que o endpoint já não escuta (event_not_subscribed) ou já não cobre (event_out_of_scope), e uma tentativa sem evento guardado (delivery_not_replayable).get_deliveryindica essa resposta de antemão comoreplayRefusal.
A gem nunca repete replay_delivery por iniciativa própria, porque uma repetição após uma resposta perdida enviaria o evento outra vez.
Parâmetros: webhooks.create
urlStringobrigatório- Para onde as entregas são feitas por POST. Apenas HTTPS, e o host não pode ser `localhost`, um nome `.localhost`, `.local` ou `.internal`, nem um literal de IP de loopback, privado, CGNAT ou link-local. Isto é um pedido do lado do servidor para um endereço que você fornece, por isso esses dão um 422 `invalid_webhook_url` em `url`. A verificação lê o hostname tal como foi escrito, e cada entrega volta a resolver o host e recusa enviar para um endereço num desses intervalos. As entregas nunca seguem redirecionamentos, por isso registe o endereço final. O que fica guardado é a serialização, feita pelo analisador de URLs, do que enviou, por isso `https://acme.com` é lido de volta como `https://acme.com/`.
eventTypesArray<String>- Que eventos chegam a este endpoint: quaisquer dos valores em `OpenEmail::WEBHOOK_EVENTS`. `create` limita o Array ao número de eventos que existem, por isso um a mais dá um 422 em `eventTypes`, e `update` não o limita. Só o comprimento é limitado, e um nome repetido é guardado e lido de volta exatamente como o enviou. Omitido ou vazio, é guardado como uma lista vazia, e é por isso que se lê de volta como `["*"]`, e significa todos os eventos `email.*` exceto `email.replied`, catorze hoje, e nunca as famílias de domínio, de supressão, de ficheiros ou de formulários. Uma família acrescentada mais tarde nunca chega a um endpoint que não a nomeou, para que uma integração não possa começar a receber uma forma que nunca viu por causa de um lançamento.
descriptionString- Uma etiqueta para o endpoint, com 200 caracteres no máximo, para que uma lista de webhooks se leia como nomes em vez de uma coluna de URLs. Omitida, é guardada e devolvida como nil.
addressAllowlistArray<String>- Endereços individuais sobre os quais este endpoint é avisado. Um evento é entregue quando o endereço a que diz respeito está nesta lista, ou quando o seu domínio está em `domainAllowlist`. Deixe ambos vazios e o endpoint é avisado sobre todos os endereços do espaço de trabalho. No máximo 50, e um endereço que não pertença a este espaço de trabalho dá um 422 `invalid_parameter`.
domainAllowlistArray<String>- Domínios inteiros sobre os quais este endpoint é avisado, incluindo os endereços que lhes forem adicionados mais tarde. Um domínio também traz os seus próprios eventos `domain.*`. No máximo 25.
api_keyString- Cria o endpoint com esta chave em vez da chave do cliente.
Resposta: o endpoint criado
Um Hash com chaves Symbol. get, list e update devolvem a mesma forma sem secret.
objectString- Sempre `webhook`, o mesmo discriminador que uma leitura simples devolve, porque o segredo é uma chave a mais na forma habitual e não um tipo de objeto próprio. Se `secret` está presente decide-se pelo método que chamou, não por este campo.
idString- O identificador do endpoint: `whe_` seguido de 24 caracteres hexadecimais. Todas as outras chamadas de webhook o recebem: `get`, `update`, `delete`, `rotate_secret`, `test`, `list_deliveries`, `list_all_deliveries`, `iterate_deliveries`, `get_delivery` e `replay_delivery`.
urlString- O endpoint tal como ficou guardado, depois de passar as verificações de HTTPS e de hosts bloqueados. É o URL analisado e novamente serializado, por isso compare com este valor e não com a String que enviou.
descriptionString or nil- A etiqueta que lhe deu, ou nil se não deu nenhuma. Um `update` que envie `description: nil` apaga-a.
eventTypesArray<String>- Os eventos subscritos, ou `["*"]` quando o endpoint não nomeou nenhum. `["*"]` é a forma como uma lista vazia guardada é apresentada na leitura e não pode ser enviado de volta, e representa os catorze eventos de mensagem e não o catálogo inteiro. `create` e `update` aceitam apenas os nomes literais dos eventos.
enabledBoolean- Indica se as entregas são tentadas. Um endpoint desativado é ignorado quando os eventos são despachados e mantém o seu segredo e o seu histórico de entregas. Aqui é sempre true, uma vez que só `update` aceita `enabled`.
disabledAtString or nil- Quando o servidor desligou o endpoint após 100 entregas falhadas seguidas. É nil enquanto está ligado, e quando foi você a desligá-lo.
disabledReasonString or nil- Porque é que o servidor o desligou. É nil sempre que `disabledAt` for nil.
consecutiveFailuresInteger- Entregas falhadas seguidas. Qualquer evento entregue repõe-no a 0, tal como `update` com `enabled: true`.
addressAllowlistArray<String>- Os endereços individuais sobre os quais este endpoint é avisado.
domainAllowlistArray<String>- Os domínios inteiros sobre os quais este endpoint é avisado. Com as duas listas vazias, é avisado sobre todos os endereços do espaço de trabalho.
lastDeliveryAtString or nil- Carimbo temporal ISO 8601 da última TENTATIVA de entrega, e não do último sucesso. É registado também depois de um POST falhado, por isso diz-lhe que o endpoint foi tentado, e `list_deliveries` diz-lhe como correu. É nil até à primeira tentativa, e por isso sempre nil em `create`.
createdAtString- Timestamp ISO 8601 de quando o endpoint foi registado. `list` devolve os endpoints do mais recente para o mais antigo por este campo.
secretString- A chave HMAC-SHA-256 que assina o `X-OpenEmail-Signature` de cada entrega: `whsec_` seguido de 43 caracteres base64url, e o que passa a `OpenEmail.verify_webhook_signature`, prefixo incluído. Devolvida por `create` e `rotate_secret` e por mais nada. Uma leitura nunca a repete, por isso guarde-a já. Um segredo perdido só pode ser substituído com `rotate_secret`, que invalida o antigo imediatamente.
Filtrar os registos
failed = client.webhooks.list_workspace_deliveries(status: "failed", since: Time.now - 86_400)p failed.items.map { |delivery| [delivery[:endpointId], delivery[:eventType], delivery[:responseCode]] } history = client.webhooks.list_activity("whe_3f9c2a7b1e4d8f60a5c7b92d")p history.items.map { |change| [change[:type], change.dig(:actor, :label)] }list_deliveries lê um endpoint e list_workspace_deliveries todos os endpoints, ou os que endpoint_ids: nomeia, e ambos aceitam status:, since: e until:, os filtros do separador Entregas da consola. list_activity e list_workspace_activity leem o registo de auditoria: quem criou, alterou, ativou ou desativou, rodou, testou, reenviou ou removeu o quê. Cada um tem ao lado uma versão list_all_ e uma iterate_, e cada linha do registo do espaço de trabalho traz endpointId. webhooks.stats devolve os números por trás do separador Análises para um período à sua escolha.
since: e until: aceitam um Time, um DateTime ou um instante ISO 8601 como String, e uma Date do Ruby significa a meia-noite UTC desse dia. until é uma palavra-chave do Ruby, mas funciona como argumento nomeado como qualquer outro: list_deliveries(id, since: start, until: finish).