curl --request POST \
--url https://api.example.com/_webhooks/otp-failed \
--header 'Content-Type: application/json' \
--data '
{
"eventType": "otp.failed",
"requestId": "<string>",
"issuerDid": "<string>",
"user": {
"contact": "<string>",
"id": "<string>",
"internalId": "<string>"
},
"api_version": "<string>",
"otp": {
"resendEndpoint": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
},
"internalId": "<string>"
}
'import requests
url = "https://api.example.com/_webhooks/otp-failed"
payload = {
"eventType": "otp.failed",
"requestId": "<string>",
"issuerDid": "<string>",
"user": {
"contact": "<string>",
"id": "<string>",
"internalId": "<string>"
},
"api_version": "<string>",
"otp": {
"resendEndpoint": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
},
"internalId": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
eventType: 'otp.failed',
requestId: '<string>',
issuerDid: '<string>',
user: {contact: '<string>', id: '<string>', internalId: '<string>'},
api_version: '<string>',
otp: {resendEndpoint: '<string>', error: {code: '<string>', message: '<string>'}},
internalId: '<string>'
})
};
fetch('https://api.example.com/_webhooks/otp-failed', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/_webhooks/otp-failed",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'eventType' => 'otp.failed',
'requestId' => '<string>',
'issuerDid' => '<string>',
'user' => [
'contact' => '<string>',
'id' => '<string>',
'internalId' => '<string>'
],
'api_version' => '<string>',
'otp' => [
'resendEndpoint' => '<string>',
'error' => [
'code' => '<string>',
'message' => '<string>'
]
],
'internalId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/_webhooks/otp-failed"
payload := strings.NewReader("{\n \"eventType\": \"otp.failed\",\n \"requestId\": \"<string>\",\n \"issuerDid\": \"<string>\",\n \"user\": {\n \"contact\": \"<string>\",\n \"id\": \"<string>\",\n \"internalId\": \"<string>\"\n },\n \"api_version\": \"<string>\",\n \"otp\": {\n \"resendEndpoint\": \"<string>\",\n \"error\": {\n \"code\": \"<string>\",\n \"message\": \"<string>\"\n }\n },\n \"internalId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/_webhooks/otp-failed")
.header("Content-Type", "application/json")
.body("{\n \"eventType\": \"otp.failed\",\n \"requestId\": \"<string>\",\n \"issuerDid\": \"<string>\",\n \"user\": {\n \"contact\": \"<string>\",\n \"id\": \"<string>\",\n \"internalId\": \"<string>\"\n },\n \"api_version\": \"<string>\",\n \"otp\": {\n \"resendEndpoint\": \"<string>\",\n \"error\": {\n \"code\": \"<string>\",\n \"message\": \"<string>\"\n }\n },\n \"internalId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/_webhooks/otp-failed")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"eventType\": \"otp.failed\",\n \"requestId\": \"<string>\",\n \"issuerDid\": \"<string>\",\n \"user\": {\n \"contact\": \"<string>\",\n \"id\": \"<string>\",\n \"internalId\": \"<string>\"\n },\n \"api_version\": \"<string>\",\n \"otp\": {\n \"resendEndpoint\": \"<string>\",\n \"error\": {\n \"code\": \"<string>\",\n \"message\": \"<string>\"\n }\n },\n \"internalId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyOTP Failed Event
Fired when an OTP SMS could not be delivered: every eligible SMS provider was tried (synchronously or via carrier delivery reports) and none succeeded. Email OTP failures do not emit this event. Carrier delivery reports are asynchronous and occasionally corrected to “delivered” afterwards, so treat this event as Humanos stopped retrying, not as a guarantee the SMS never arrived. The safe reaction is to PATCH the otp.resendEndpoint URL exactly as delivered — a resend issues a fresh code and invalidates the old one, so it is harmless even if the original message did arrive late.
Inbound webhook callback — Humanos POSTs this payload to your registered webhook URL. This is not an endpoint you call; it is documented as a path so SDK code generators emit a typed payload model.
curl --request POST \
--url https://api.example.com/_webhooks/otp-failed \
--header 'Content-Type: application/json' \
--data '
{
"eventType": "otp.failed",
"requestId": "<string>",
"issuerDid": "<string>",
"user": {
"contact": "<string>",
"id": "<string>",
"internalId": "<string>"
},
"api_version": "<string>",
"otp": {
"resendEndpoint": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
},
"internalId": "<string>"
}
'import requests
url = "https://api.example.com/_webhooks/otp-failed"
payload = {
"eventType": "otp.failed",
"requestId": "<string>",
"issuerDid": "<string>",
"user": {
"contact": "<string>",
"id": "<string>",
"internalId": "<string>"
},
"api_version": "<string>",
"otp": {
"resendEndpoint": "<string>",
"error": {
"code": "<string>",
"message": "<string>"
}
},
"internalId": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
eventType: 'otp.failed',
requestId: '<string>',
issuerDid: '<string>',
user: {contact: '<string>', id: '<string>', internalId: '<string>'},
api_version: '<string>',
otp: {resendEndpoint: '<string>', error: {code: '<string>', message: '<string>'}},
internalId: '<string>'
})
};
fetch('https://api.example.com/_webhooks/otp-failed', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/_webhooks/otp-failed",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'eventType' => 'otp.failed',
'requestId' => '<string>',
'issuerDid' => '<string>',
'user' => [
'contact' => '<string>',
'id' => '<string>',
'internalId' => '<string>'
],
'api_version' => '<string>',
'otp' => [
'resendEndpoint' => '<string>',
'error' => [
'code' => '<string>',
'message' => '<string>'
]
],
'internalId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/_webhooks/otp-failed"
payload := strings.NewReader("{\n \"eventType\": \"otp.failed\",\n \"requestId\": \"<string>\",\n \"issuerDid\": \"<string>\",\n \"user\": {\n \"contact\": \"<string>\",\n \"id\": \"<string>\",\n \"internalId\": \"<string>\"\n },\n \"api_version\": \"<string>\",\n \"otp\": {\n \"resendEndpoint\": \"<string>\",\n \"error\": {\n \"code\": \"<string>\",\n \"message\": \"<string>\"\n }\n },\n \"internalId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/_webhooks/otp-failed")
.header("Content-Type", "application/json")
.body("{\n \"eventType\": \"otp.failed\",\n \"requestId\": \"<string>\",\n \"issuerDid\": \"<string>\",\n \"user\": {\n \"contact\": \"<string>\",\n \"id\": \"<string>\",\n \"internalId\": \"<string>\"\n },\n \"api_version\": \"<string>\",\n \"otp\": {\n \"resendEndpoint\": \"<string>\",\n \"error\": {\n \"code\": \"<string>\",\n \"message\": \"<string>\"\n }\n },\n \"internalId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/_webhooks/otp-failed")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"eventType\": \"otp.failed\",\n \"requestId\": \"<string>\",\n \"issuerDid\": \"<string>\",\n \"user\": {\n \"contact\": \"<string>\",\n \"id\": \"<string>\",\n \"internalId\": \"<string>\"\n },\n \"api_version\": \"<string>\",\n \"otp\": {\n \"resendEndpoint\": \"<string>\",\n \"error\": {\n \"code\": \"<string>\",\n \"message\": \"<string>\"\n }\n },\n \"internalId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyHeaders
Pin request, response, and webhook shapes to a specific dated API version (YYYY-MM-DD). Omit to use the version pinned to your API key (set when the key is created; new keys default to the latest version). New integrations should target the latest version.
^\d{4}-\d{2}-\d{2}$"2026-07-06"
Body
Response
Webhook received successfully