# 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](report-verification.html#otp-verification-api-report).

## 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](get-verification-status-by-number.html#otp-verification-api-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 number has no verification under the OTP application, the API returns `404 Not
Found`. Use [Get verification status by
number](get-verification-status-by-number.html#otp-verification-api-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](index.html#otp-verification-object-reference) 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 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](errors.html#otp-verification-api-errors) 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](../authentication.html#otp-verification-authentication) for credential and header
requirements.

The SDK examples assume that the corresponding SDK is installed and initialized. See the
[Ruby](../sdks/ruby.html#otp-verification-sdk-ruby),
[Python](../sdks/python.html#otp-verification-sdk-python),
[Node.js](../sdks/node.html#otp-verification-sdk-node),
[PHP](../sdks/php.html#otp-verification-sdk-php),
[iOS](../sdks/ios.html#otp-verification-sdk-ios),
[Android](../sdks/android.html#otp-verification-sdk-android),
[React Native](../sdks/react-native.html#otp-verification-sdk-react-native), and
[Dart](../sdks/dart.html#otp-verification-sdk-dart) SDK pages.

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.

SMS

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:05:00.000Z",
    "sms": {
      "template": "Your code is {{CODE}}",
      "language": "en-US",
      "interception_timeout": 300,
      "code_length": 6
    }
  }
}
```


Phone call

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:05:00.000Z",
    "callout": {
      "language": "de-DE",
      "code_length": 6
    }
  }
}
```

### 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.

SMS

```
result = client.report_verification_by_number(
  "+4915112345678",
  delivery_method: "sms",
  code:            "123456"
)

result.status    # => "verified"
result.verified? # => true
```


Phone call

```
result = client.report_verification_by_number(
  "+4915112345678",
  delivery_method: "callout",
  code:            "123456"
)

result.status    # => "verified"
result.verified? # => true
```

### Python SDK

The Python SDK sends a `PATCH` request when `report_verification_by_number(...)` is
called. It percent-encodes the number for the path and returns the updated `Verification`.

SMS

```
result = client.report_verification_by_number(
    "+4915112345678",
    delivery_method="sms",
    code="123456",
)

result.status  # "verified"
```


Phone call

```
result = client.report_verification_by_number(
    "+4915112345678",
    delivery_method="callout",
    code="123456",
)

result.status  # "verified"
```

The SDK does not normalize or validate the number. If the number has no verification, it raises
`DidwwNotFoundError`.

### Node.js SDK

The Node.js SDK sends a `PATCH` request when `reportVerificationByNumber(...)` is called
and returns the updated verification.

SMS

```
const result = await client.reportVerificationByNumber('+4915112345678', {
  deliveryMethod: 'sms',
  code: '123456',
});

result.status; // 'verified'
```


Phone call

```
const result = await client.reportVerificationByNumber('+4915112345678', {
  deliveryMethod: 'callout',
  code: '123456',
});

result.status; // 'verified'
```

If a by-number report times out, call `getVerificationByNumber` rather than sending it
again: the first request may already have consumed an attempt.

### PHP SDK

The PHP SDK sends a `PATCH` request when `reportVerificationByNumber(...)` is called. It
sends only the digits of the number in the path and returns the updated `Verification`.

SMS

```
$result = $client->reportVerificationByNumber('+4915112345678', DeliveryMethod::Sms, '123456');

$result->status; // "verified"
```


Phone call

```
$result = $client->reportVerificationByNumber('+4915112345678', DeliveryMethod::Callout, '123456');

$result->status; // "verified"
```

A number with no digits throws `ConfigurationException` before anything is sent. If the number
has no verification, the SDK throws `NotFoundException`.

### 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.

SMS

```
let result = try await client.verify(
    number: "+49 151 1234 5678",
    code: "123456",
    method: .sms
)

result.status // .verified
```


Phone call

```
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.

SMS

```
val handle = didww.resume(
    destination = "+4915112345678",
    method = DeliveryMethod.SMS,
)

handle.submit("123456")
```


Phone call

```
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.

### Dart SDK

The Dart SDK sends a `PATCH` request when `reportVerificationByNumber(...)` is called.
The reported value is wrapped in a `ReportValue`.

SMS

```
final finished = await client.reportVerificationByNumber(
  '+4915112345678',
  deliveryMethod: DeliveryMethod.sms,
  value: const ReportValue.code('123456'),
);

finished.knownStatus; // VerificationStatus.verified
```


Phone call

```
final finished = await client.reportVerificationByNumber(
  '+4915112345678',
  deliveryMethod: DeliveryMethod.callout,
  value: const ReportValue.code('123456'),
);

finished.knownStatus; // VerificationStatus.verified
```

With `VerificationSession`, call `session.resumeByNumber(destination)` first and then
`session.submit(code)`; the session then holds the verification and reports against it.

### React Native SDK

The React Native SDK has no direct by-number report call. Resume the verification for the
number through the `useVerification()` controller, then submit against the resumed
verification:

```
controller.resume({ destination: '+4915112345678', deliveryMethod: 'sms' });

// once state.kind is 'awaitingInput'
controller.submit('123456');
```

The delivery method returned by the API remains authoritative. The `deliveryMethod`
argument to `resume(...)` selects channel-specific client behavior, including automatic SMS
capture on Android.

On this page
