Report a verification by number#
Submit the code the user received by SMS or phone call without supplying a verification
id. The endpoint identifies the verification associated with the destination number and
checks the submitted code against it.
Use this endpoint when your application kept the destination number but did not store the
verification id returned by the start request. To report against one specific
verification, use Report a verification.
Request#
HTTP method: PATCH (PUT is accepted as an alias)
Path: /api/v1/verifications/by_number/{number}
Path parameters#
Name |
Type |
Description |
|---|---|---|
|
|
Destination phone number in E.164 format. The leading |
Request body#
The request body contains a top-level data object. Use code for both sms and
callout.
Field |
Type |
Required |
Description |
|---|---|---|---|
|
|
Yes |
Must match the method used to start the verification. Supported values are |
|
|
Yes |
The code the user received by SMS or phone call. |
Which verification receives the report#
The report is scoped to the authenticated OTP application and the supplied phone number, and targets the most recently created verification for that number, whatever its status. It is the same record that Get verification status by number returns.
If another verification is started for the same number before the report is submitted, that newer verification becomes the target of a later by-number report. Use the by-id report endpoint when the submission must be tied to the exact verification originally shown to the user.
When the targeted verification has already finished, the report does not change its outcome.
Read status and id from the response to confirm which verification the report reached
and what state it is in.
If the API cannot resolve a verification that can receive the report, it returns 404 Not
Found. Use Get verification status by number when you need to retrieve the latest state without
submitting a code.
Response#
When the API accepts the report request, it returns 200 OK with the
verification object under a top-level data
key. Authentication, lookup, and validation errors return an errors array.
The following table lists the HTTP status codes returned by this endpoint:
Status |
Meaning |
|---|---|
|
The report was processed. Inspect the returned |
|
Authentication failed, credentials are missing or invalid, or the authentication mode is below the minimum configured for the OTP application. |
|
No verification that can receive the report exists for the specified number under the OTP application. |
|
The submitted report could not be accepted. This includes an incorrect code or a
mismatched |
A correct code returns 200 OK with status verified. An incorrect code returns
422 Unprocessable Content with code_invalid. The verification remains available for
another report until the attempt limit is reached. After three unsuccessful reports, it
becomes failed with error_code too_many_attempts.
If the challenge has not yet been dispatched, the API can return 422 Unprocessable
Content with not_ready_to_report. Submit the value again after the challenge has been
sent or the call has been placed.
See Errors and status codes for the error response structure and available error codes.
Warning
Each report can consume one of the three allowed attempts. Do not automatically retry a report after a timeout or another ambiguous network failure. Check the verification status before deciding whether the user should submit the value again.
Examples#
The REST API examples use HTTP Basic authentication. See REST API authentication for credential and header requirements.
The SDK examples assume that the corresponding SDK is installed and initialized. See the Ruby SDK, iOS SDK, and Android SDK.
The identifiers, expiration times, fees, and codes shown in the examples are illustrative.
REST API#
Send a PATCH request with the destination number in the path and the value reported by
the user. The examples omit the leading + so no path encoding is required.
http
PATCH /api/v1/verifications/by_number/4915112345678 HTTP/1.1
Host: verification.didww.com
Content-Type: application/json
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==
{
"data": {
"delivery_method": "sms",
"code": "123456"
}
}
curl
curl -i -X PATCH https://verification.didww.com/api/v1/verifications/by_number/4915112345678 -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"data": {"code": "123456", "delivery_method": "sms"}}' --user your_app_key:your_app_secret
response
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"id": "0f9c8b7a-1e2d-4c3b-9a8f-7e6d5c4b3a21",
"destination": "4915112345678",
"delivery_method": "sms",
"fee": "0.06",
"status": "verified",
"error_code": null,
"error_detail": null,
"expires_at": "2026-07-15T10:02:00.000Z",
"sms": {
"template": "Your code is {{CODE}}",
"language": "en-US",
"interception_timeout": 120
}
}
}
http
PATCH /api/v1/verifications/by_number/4915112345678 HTTP/1.1
Host: verification.didww.com
Content-Type: application/json
Accept: application/json
Authorization: Basic eW91cl9hcHBfa2V5OnlvdXJfYXBwX3NlY3JldA==
{
"data": {
"delivery_method": "callout",
"code": "123456"
}
}
curl
curl -i -X PATCH https://verification.didww.com/api/v1/verifications/by_number/4915112345678 -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"data": {"code": "123456", "delivery_method": "callout"}}' --user your_app_key:your_app_secret
response
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"id": "2b3c4d5e-6f70-4b3c-9d0e-1f2a3b4c5d6e",
"destination": "4915112345678",
"delivery_method": "callout",
"fee": "0.08",
"status": "verified",
"error_code": null,
"error_detail": null,
"expires_at": "2026-07-15T10:02:00.000Z",
"callout": {
"language": "de-DE"
}
}
}
Ruby SDK#
The Ruby SDK sends a PATCH request when report_verification_by_number(...) is called.
It handles path encoding and returns the updated verification object.
result = client.report_verification_by_number(
"+4915112345678",
delivery_method: "sms",
code: "123456"
)
result.status # => "verified"
result.verified? # => true
result = client.report_verification_by_number(
"+4915112345678",
delivery_method: "callout",
code: "123456"
)
result.status # => "verified"
result.verified? # => true
iOS SDK#
The iOS SDK sends a PUT request and returns a VerificationResult. It normalizes the
supplied number to digits before building the request path. Code submissions require the
delivery method.
let result = try await client.verify(
number: "+49 151 1234 5678",
code: "123456",
method: .sms
)
result.status // .verified
let result = try await client.verify(
number: "+49 151 1234 5678",
code: "123456",
method: .callout
)
result.status // .verified
If the number contains no digits, the SDK throws VerificationError.invalidNumber before
sending a request. A wrong .sms or .callout selection is detected by the API and
returned as a validation error.
Android SDK#
The Android SDK reports by number through a handle returned by resume(...). The first
collection of handle.states looks up the verification by number. A later submission from
that handle is sent to the same by-number path.
The examples submit the value before collection. This is supported because the handle buffers the value until the lookup completes and the verification can accept it.
val handle = didww.resume(
destination = "+4915112345678",
method = DeliveryMethod.SMS,
)
handle.submit("123456")
val handle = didww.resume(
destination = "+4915112345678",
method = DeliveryMethod.CALLOUT,
)
handle.submit("123456")
Collect the returned handle exactly once:
viewModelScope.launch {
handle.states.collect { state ->
when (state) {
is VerificationState.AwaitingInput ->
state.lastError?.let { println("try again: ${it.detail}") }
VerificationState.Submitting ->
println("checking")
is VerificationState.Verified ->
println("verified")
is VerificationState.Failed ->
println("failed: ${state.reason}")
VerificationState.Expired ->
println("expired")
else -> Unit
}
}
}
For a correct value, the flow progresses through Starting, AwaitingInput,
Submitting, and Verified. If the API rejects the value but allows another attempt,
the flow returns to AwaitingInput with lastError set. If the lookup finds a finished
verification, the flow emits that terminal state and does not send the buffered report.
The delivery method returned by the API remains authoritative. The method argument to
resume(...) selects channel-specific client behavior, including automatic SMS capture.