## API URL
URL used to send HTTP requests:
```url
https://portal.bulkgate.com/api/1.0/otp/send
```

> [!NOTE]
> If the request does not reach its destination, repeat it on the [backup server](https://www.bulkgate.com/en/docs/api-administration-tokens/api-backup-server/) `backup1.bulkgate.com`.

## Supported HTTP methods

- `POST` - `application/json`

```http
POST /api/1.0/otp/send HTTP/1.1
Host: portal.bulkgate.com
Content-Type: application/json
```

> [!IMPORTANT]
> On top of `request_quota_number` the endpoint enforces an **account-wide limit of 60 requests per minute**. Exceeding it returns `the_quota_of_send_per_minute_has_been_exceeded`.

## Parameters table

| PARAMETER NAME                | VALUE                                                                                                                                                                                                                                        | MANDATORY | DEFAULT VALUE                                                                                                                               |
|:------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------|:--------------------------------------------------------------------------------------------------------------------------------------------|
| application_id                | [Application ID](https://www.bulkgate.com/en/docs/api-administration-tokens/api-administration/)                                                                                                                                                                                                | **Yes**   | -                                                                                                                                           | 
| application_token             | [Application token](https://www.bulkgate.com/en/docs/api-administration-tokens/api-tokens/)	                                                                                                                                                                                                    | **Yes**   | -                                                                                                                                           |
| number                        | Phone number to which send the verification code                                                                                                                                                                                             | **Yes**   | -                                                                                                                                           |
| country                       | Country code of phone number                                                                                                                                                                                                                 | no        | The value is taken from the profile.                                                                                                        |
| language                      | Language of the message text, one of the 100 supported ISO codes. An unknown code rejects the request. Without it the language is detected from the phone number.                                                                                                                                                | no        | `null`                                                                                                                                       |
| code_type                     | Type of code. (`string`, `int`, or `combined`)                                                                                                                                                                                               | no        | `int`                                                                                                                                       |
| code_length                   | Length of verification code (4-100).                                                                                                                                                                                                         | no        | 6                                                                                                                                           |
| request_quota_number          | The number of requests per minute for `request_quota_identification`                                                                                                                                                                         | no        | 1                                                                                                                                           |
| request_quota_identification  | Identification of the "OTP user / requester" to whom the `request_quota_number` quota per minute will apply. We recommend using an IP address for this identification.                                                                       | **Yes**   | -                                                                                                                                           |
| trials_available_resend       | Limit of available [resends](https://www.bulkgate.com/en/docs/otp-api/one-time-password-resend/)                                                                                                                                                                         | no        | `null` - unlimited                                                                                                                          |
| trials_available_verification | Limit of available [verification](https://www.bulkgate.com/en/docs/otp-api/one-time-password-verify/)                                                                                                                                                                    | no        | `null` - unlimited                                                                                                                          |
| daily_limit                   | Limit of available requests per day (sliding for last 24 hours)                                                                                                                                                                              | no        | `null` - unlimited                                                                                                                          |
| daily_limit_country           | Daily limit per country as a map `{"cz": 100, "sk": 50}`. When filled in, **only** the listed countries are allowed — any other one fails with `country_is_disabled`. | no        | `null` - unlimited                                                                                                                          |
| expiration                    | Expiration of OTP request in seconds, after completion of this time request is not possible. A value below `60` is ignored and the default is used.                                                                                                                                                 | no        | `604800` - 7 days                                                                                                                           |
| channel                       | Alternative channels. Channels are listed in a cascade, if we are unable to deliver your message via highest priority channel, channels lower in the cascade list will be used. If none of them manages to deliver sms will be used instead. | no        | [SMS](#sms-object), [Viber](#viber-object), [RCS](#rcs-object), [WhatsApp](#whatsapp-object) or [Text2Voice](#text2voice-object) |


## Channels

The `channel` object decides which channels deliver the code and in what order. **The order of the keys in the request is the order of the cascade** — if the first channel cannot deliver the code, the next one is tried. If none of them can, SMS is used.

### SMS object
| PARAMETER NAME  | VALUE                                                                                                                                                             | MANDATORY | DEFAULT VALUE |
|:----------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------|:--------------|
| sender_id       | Sender ID, see [sender ID type](https://www.bulkgate.com/en/docs/simple-api/simple-transactional/)                                                                                               | no        | `gSystem`     |
| sender_id_value | Sender value - `gOwn` (e.g. "420 777 777 777"), `gText` (e.g. "BulkGate"), `gProfile` (e.g. "423"), `gMobile` or `gPush` [(KEY)](https://www.bulkgate.com/en/helpdesk/mobile-connect/mobile-connect-install/) | no        | `null`        |
| domain          | Url of a website that uses [WebOTP](https://developer.mozilla.org/en-US/docs/Web/API/WebOTP_API) for auto input of received code.                                                                                                | no        | `null`        |



### Viber object
| PARAMETER NAME | VALUE                                                                          | MANDATORY | DEFAULT VALUE |
|:---------------|:-------------------------------------------------------------------------------|:----------|:--------------|
| sender         | Name of your registered [sender for Viber](https://www.bulkgate.com/en/helpdesk/viber/sender-registration-viber/) | **Yes**   | -             |
| expiration     | Seconds to wait until trying another channel                                   | no        | 60            |
| code_type      | Code type required by Viber, stated on the approved OTP template.              | no        | `null`        |
| code_reason    | Reason for sending the code, required by Viber.                                | no        | `null`        |
| business_name  | Business name shown in the message.                                            | no        | `null`        |

### RCS object
| PARAMETER NAME | VALUE                                                                          | MANDATORY | DEFAULT VALUE |
|:---------------|:-------------------------------------------------------------------------------|:----------|:--------------|
| sender         | Text sender for RCS. It must be registered first — contact [our support](https://www.bulkgate.com/en/contact-us/) to register it.   | **Yes**   | -             |
| expiration     | Seconds to wait until trying another channel                                   | no        | 60            |
| use_card       | Sends the code as a card instead of plain text.                                | no        | `false`       |

### WhatsApp object

| PARAMETER NAME | VALUE                                                                                      | MANDATORY | DEFAULT VALUE       |
|:---------------|:---------------------------------------------------------------------------------------------|:----------|:--------------------|
| sender         | Your registered [WhatsApp sender](https://www.bulkgate.com/en/helpdesk/whatsapp/sender-registration-whatsapp/)               | **Yes**   | -                   |
| template       | Name of the approved WhatsApp template used to deliver the code.                           | No        | `verification_code` |
| language       | Template language. Without it the request-level `language` is used.                        | No        | `null`              |
| expiration     | Seconds to wait until trying another channel in the cascade. Minimum `60`.                 | No        | `180`               |

### Text2Voice object

The code is read out loud. The message can be repeated so the recipient can write it down.

| PARAMETER NAME   | VALUE                                                                        | MANDATORY | DEFAULT VALUE |
|:-----------------|:--------------------------------------------------------------------------------|:----------|:--------------|
| sender           | Your registered caller number.                                               | **Yes**   | -             |
| language         | Voice language, one of the 47 supported ISO codes. Without it the request-level `language` is used. | No | `null` |
| prefer_gender    | Preferred voice - `male` or `female`.                                        | No        | `male`        |
| safety_statement | Prepends a safety notice to the call.                                        | No        | `true`        |
| repeat           | How many times the code is repeated during the call.                         | No        | `1`           |
| expiration       | Seconds to wait until trying another channel in the cascade. Minimum `60`.   | No        | `180`         |

## Example request

```json
{
  "application_id": 451,
  "application_token": "NKN02TWE6NfBkfl-your-secret-token-Wf05GaqLIWLW4aBj",
  "number": "44777777777",
  "country": "gb",
  "language": "en",
  "code_type": "string",
  "code_length": 7,
  "request_quota_number": 1,
  "request_quota_identification": "127.0.0.1",
  "trials_available_resend": 2,
  "trials_available_verification": 5,
  "daily_limit": 100,
  "daily_limit_country": {"cz": 150, "sk": 50},
  "expiration": 3600,
  "channel": {
    "rcs": {
      "sender": "Lt. Hagan",
      "expiration": 100
    },
    "viber": {
      "sender": "Lt. Hagan",
      "expiration": 100
    },
    "sms": {
      "sender_id": "gText",
      "sender_id_value": "Lt-Hagan",
      "unicode": true
    }
  }
}
```

## Response

**In case of success:**
```json
{
    "data": {
        "id": "otp-65cca8b4b6a6a2.24308291",
        "message": {
          "status": "accepted",
          "message_id": "cascade-xjyjzh7thor3",
          "part_id": [
            "cascade-xjyjzh7thor3"  
          ],
          "number": "420777777777",
          "channel": "whatsapp"
        }
    }
}
```

**In case of error:**
```json
{
    "type": "unknown_identity",
    "code": 400,
    "error": "Unknown identity",
    "detail": null
}
```

```json
{
    "type": "invalid_input_parameters",
    "code": 400,
    "error": "Invalid input parameters",
    "detail": null
}
```

Where:

- **type** and **error** (description of the error) can be found in the [error types table](https://www.bulkgate.com/en/docs/api-administration-tokens/api-error-types/)
- **code** represents http error
- **detail** is an additional info about the error

### OTP API error types

On top of the [common types](https://www.bulkgate.com/en/docs/api-administration-tokens/api-error-types/) the OTP API returns its own:

| TYPE                                                         | WHEN IT HAPPENS                                                      |
|:-------------------------------------------------------------|:----------------------------------------------------------------------|
| `the_quota_of_send_per_minute_has_been_exceeded`             | The per-minute send quota is used up.                                 |
| `the_quota_of_one_additional_resend_per_minute_has_been_exceeded` | A resend sooner than 60 s after the previous one.                 |
| `the_quota_of_one_additional_resend_has_been_exceeded`       | `trials_available_resend` is used up.                                 |
| `the_quota_of_one_additional_verification_has_been_exceeded` | `trials_available_verification` is used up.                           |
| `daily_limit_reached`                                        | `daily_limit` is used up.                                             |
| `country_is_disabled`                                        | The number's country is not listed in `daily_limit_country`.          |
| `country_daily_limit_exceeded`                               | The daily limit for that country is used up.                          |
| `invalid_phone_number`                                       | The number could not be recognised.                                   |
| `invalid_code`                                               | The verified code does not match.                                     |
| `unknown_channel`                                            | The cascade contains a channel the OTP API does not know.             |
| `request_can_not_be_created`                                 | The request could not be created.                                     |
