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

number

string

Destination phone number in E.164 format. The leading + is optional. When the leading + is included in the URL path, percent-encode it as %2B.

Request body#

The request body contains a top-level data object. Use code for both sms and callout.

Field

Type

Required

Description

delivery_method

string

Yes

Must match the method used to start the verification. Supported values are sms and callout.

code

string

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

200 OK

The report was processed. Inspect the returned status and error_code to determine the current verification state.

401 Unauthorized

Authentication failed, credentials are missing or invalid, or the authentication mode is below the minimum configured for the OTP application.

404 Not Found

No verification that can receive the report exists for the specified number under the OTP application.

422 Unprocessable Content

The submitted report could not be accepted. This includes an incorrect code or a mismatched delivery_method.

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.