# Contact Verification

## Contact verification

> \*\*Introduction\*\*\
> \
> The contact verification api provides insight into how credible the number is.\
> \
> \### \`date\`\
> \
> \*\*Type:\*\* \`string\` (ISO 8601 timestamp)\
> \*\*Example:\*\* \`2025-06-21T17:21:56.526Z\`\
> \*\*Description:\*\* The exact date and time when this record was generated or last updated.\
> \
> \*\*\*\
> \
> \### \`msisdn\`\
> \
> \*\*Type:\*\* \`string\`\
> \*\*Format:\*\* Country code + subscriber number (no separators)\
> \*\*Example:\*\* \`38591XXXXXXX\`\
> \*\*Description:\*\* Mobile Station International Subscriber Directory Number – the full telephone number including country code.\
> \
> \*\*\*\
> \
> \### \`phone\`\
> \
> An object containing detailed telecom metadata about the number.\
> \
> \| Field | Type | Example | Description |\
> \| :---- | :--- | :------ | :---------- |\
> \| \`country\_calling\_code\` | \`string\` | \`385\` | International dialing code for the country. |\
> \| \`country\_name\` | \`string\` | \`Croatia\` | Official country name. |\
> \| \`current\_network\_mobile\_code\` | \`string\` | \`01\` | Mobile network code (MNC) of the network the number is currently registered on. |\
> \| \`first\_seen\` | \`string\` | \`2017-03-05\` | Date the number was first observed in our system. |\
> \| \`current\_network\_name\` | \`string\` | \`T-Mobile\` | Human-readable name of the network the number currently uses. |\
> \| \`initial\_network\_name\` | \`string\` | \`A1\` | Name of the network where the number was first issued. |\
> \| \`initial\_network\_mobile\_code\` | \`string\` | \`10\` | Mobile network code (MNC) of the initial network. |\
> \| \`first\_ported\` | \`string\` | \`2017-03-05\` | Date the number was first ported from its original network. |\
> \| \`last\_ported\` | \`string\` | \`2024-02-06\` | Date the number was most recently ported to a different network. |\
> \| \`mobile\_country\_code\` | \`string\` | \`219\` | Mobile Country Code (MCC) assigned to the country/operator. |\
> \| \`ported\_times\` | \`integer\` | \`4\` | Total number of times the number has been ported between networks. |\
> \| \`type\` | \`string\` | \`mobile\` | Phone type; e.g. \`landline\`, \`mobile\`, \`toll\_free\`, \`shared\_cost\`, \`voip\`, \`emergency\`, \`n/a\`. |\
> \
> \### \`response\`\
> \
> \| Value | Description         | Action                                                                                                              |\
> \| :---- | :------------------ | :------------------------------------------------------------------------------------------------------------------ |\
> \| 0     | Success             | :airplane:                                                                                                          |\
> \| 1     | General error       | Repeating the request won't yield different result                                                                  |\
> \| 2     | Pricing not set     | Contact \[<procurement@bind.hr>]\(mailto:<procurement@bind.hr>)                                                           |\
> \| 3     | Out of balance      | Contact \[<procurement@bind.hr>]\(mailto:<procurement@bind.hr>)                                                           |\
> \| 4     | Throttled           | You are sending at higher rate per second than allocated. Contact \[<procurement@bind.hr>]\(mailto:<procurement@bind.hr>) |\
> \| 5     | Invalid number      | Number length not valid                                                                                             |\
> \| 6     | Not resolved        | Number cannot be resolved due to missing coverage                                                                   |\
> \| 7     | Timeout             | Number cannot be resolved due to timeout                                                                            |\
> \| 8     | Missing permissions | Contact \[<procurement@bind.hr>]\(mailto:<procurement@bind.hr>)                                                           |\
> \
> \*\*\*\
> \
> \### \`scoring\`\
> \
> An object describing quality or trust metrics for the number.\
> \
> \| Field         | Type     | Example | Description                                                 |\
> \| :------------ | :------- | :------ | :---------------------------------------------------------- |\
> \| \`credibility\` | \`string\` | \`high\`  | Values: \`very\_low\`, \`low\`, \`intermediate\`, \`high\`, \`very\_high\` |\
> \
> The higher the credibility the more the number is a credible / trusted number.\
> \
> \*\*\*\
> \
> \### \`security\`\
> \
> An object detailing any security-related flags or breach history.\
> \
> \| Field                        | Type      | Example      | Description                                                                              |\
> \| :--------------------------- | :-------- | :----------- | :--------------------------------------------------------------------------------------- |\
> \| \`data\_breaches\_count\`        | \`integer\` | \`3\`          | Number of known data breaches involving this number or associated account.               |\
> \| \`data\_breaches\_first\_breach\` | \`string\`  | \`2018-10-16\` | Date of the earliest recorded breach.                                                    |\
> \| \`data\_breaches\_last\_breach\`  | \`string\`  | \`2021-04-08\` | Date of the most recent recorded breach.                                                 |\
> \| \`is\_disposable\`              | \`string\`  | \`no\`         | Indicates whether the number is from a disposable/temporary service (\`yes\`/\`no\` / \`n/a\`) |\
> \
> \### \`social\_presence\`\
> \
> An object mapping major platforms to presence indicators.\
> \
> \- \*\*\`has\`\*\* may be:\
> &#x20; \- \`yes\` – profile found\
> &#x20; \- \`no\` – profile explicitly not found\
> &#x20; \- \`n/a\` – lookup wasn’t possible (information unavailable)\
> \- \*\*\`is\_business\`\*\* (where applicable): \`yes\`/\`no\`

```json
{"openapi":"3.1.0","info":{"title":"Contact intelligence API","version":"1.0"},"servers":[{"url":"https://number-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}},"schemas":{"MsisdnRequest":{"type":"object","required":["msisdn"],"properties":{"msisdn":{"type":"array","items":{"type":"string"},"description":"A list of MSISDNs to look up."},"callback_url":{"type":"string","format":"uri","description":"An optional URL to receive a callback with the results."}}}}},"paths":{"/lookup/contact-verification":{"post":{"summary":"Contact verification","description":"**Introduction**\n\nThe contact verification api provides insight into how credible the number is.\n\n### `date`\n\n**Type:** `string` (ISO 8601 timestamp)\n**Example:** `2025-06-21T17:21:56.526Z`\n**Description:** The exact date and time when this record was generated or last updated.\n\n***\n\n### `msisdn`\n\n**Type:** `string`\n**Format:** Country code + subscriber number (no separators)\n**Example:** `38591XXXXXXX`\n**Description:** Mobile Station International Subscriber Directory Number – the full telephone number including country code.\n\n***\n\n### `phone`\n\nAn object containing detailed telecom metadata about the number.\n\n| Field | Type | Example | Description |\n| :---- | :--- | :------ | :---------- |\n| `country_calling_code` | `string` | `385` | International dialing code for the country. |\n| `country_name` | `string` | `Croatia` | Official country name. |\n| `current_network_mobile_code` | `string` | `01` | Mobile network code (MNC) of the network the number is currently registered on. |\n| `first_seen` | `string` | `2017-03-05` | Date the number was first observed in our system. |\n| `current_network_name` | `string` | `T-Mobile` | Human-readable name of the network the number currently uses. |\n| `initial_network_name` | `string` | `A1` | Name of the network where the number was first issued. |\n| `initial_network_mobile_code` | `string` | `10` | Mobile network code (MNC) of the initial network. |\n| `first_ported` | `string` | `2017-03-05` | Date the number was first ported from its original network. |\n| `last_ported` | `string` | `2024-02-06` | Date the number was most recently ported to a different network. |\n| `mobile_country_code` | `string` | `219` | Mobile Country Code (MCC) assigned to the country/operator. |\n| `ported_times` | `integer` | `4` | Total number of times the number has been ported between networks. |\n| `type` | `string` | `mobile` | Phone type; e.g. `landline`, `mobile`, `toll_free`, `shared_cost`, `voip`, `emergency`, `n/a`. |\n\n### `response`\n\n| Value | Description         | Action                                                                                                              |\n| :---- | :------------------ | :------------------------------------------------------------------------------------------------------------------ |\n| 0     | Success             | :airplane:                                                                                                          |\n| 1     | General error       | Repeating the request won't yield different result                                                                  |\n| 2     | Pricing not set     | Contact [procurement@bind.hr](mailto:procurement@bind.hr)                                                           |\n| 3     | Out of balance      | Contact [procurement@bind.hr](mailto:procurement@bind.hr)                                                           |\n| 4     | Throttled           | You are sending at higher rate per second than allocated. Contact [procurement@bind.hr](mailto:procurement@bind.hr) |\n| 5     | Invalid number      | Number length not valid                                                                                             |\n| 6     | Not resolved        | Number cannot be resolved due to missing coverage                                                                   |\n| 7     | Timeout             | Number cannot be resolved due to timeout                                                                            |\n| 8     | Missing permissions | Contact [procurement@bind.hr](mailto:procurement@bind.hr)                                                           |\n\n***\n\n### `scoring`\n\nAn object describing quality or trust metrics for the number.\n\n| Field         | Type     | Example | Description                                                 |\n| :------------ | :------- | :------ | :---------------------------------------------------------- |\n| `credibility` | `string` | `high`  | Values: `very_low`, `low`, `intermediate`, `high`, `very_high` |\n\nThe higher the credibility the more the number is a credible / trusted number.\n\n***\n\n### `security`\n\nAn object detailing any security-related flags or breach history.\n\n| Field                        | Type      | Example      | Description                                                                              |\n| :--------------------------- | :-------- | :----------- | :--------------------------------------------------------------------------------------- |\n| `data_breaches_count`        | `integer` | `3`          | Number of known data breaches involving this number or associated account.               |\n| `data_breaches_first_breach` | `string`  | `2018-10-16` | Date of the earliest recorded breach.                                                    |\n| `data_breaches_last_breach`  | `string`  | `2021-04-08` | Date of the most recent recorded breach.                                                 |\n| `is_disposable`              | `string`  | `no`         | Indicates whether the number is from a disposable/temporary service (`yes`/`no` / `n/a`) |\n\n### `social_presence`\n\nAn object mapping major platforms to presence indicators.\n\n- **`has`** may be:\n  - `yes` – profile found\n  - `no` – profile explicitly not found\n  - `n/a` – lookup wasn’t possible (information unavailable)\n- **`is_business`** (where applicable): `yes`/`no`","operationId":"contact-verification","tags":["Contact verification"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MsisdnRequest"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["date","msisdn","response"],"properties":{"date":{"type":"string"},"msisdn":{"type":"string"},"response":{"type":"integer"},"phone":{"type":"object","properties":{"country_calling_code":{"type":"string"},"country_name":{"type":"string"},"current_network_mobile_code":{"type":"string"},"current_network_name":{"type":"string"},"first_ported":{"type":"string"},"first_seen":{"type":"string"},"initial_network_name":{"type":"string"},"initial_network_mobile_code":{"type":"string"},"last_ported":{"type":"string"},"mobile_country_code":{"type":"string"},"ported_times":{"type":"integer"},"type":{"type":"string"}}},"scoring":{"type":"object","properties":{"credibility":{"type":"string"}}},"security":{"type":"object","properties":{"data_breaches_count":{"type":"integer"},"data_breaches_first_breach":{"type":"string"},"data_breaches_last_breach":{"type":"string"},"is_disposable":{"type":"string"}}},"social_presence":{"type":"object","properties":{"amazon":{"type":"object","properties":{"has":{"type":"string"}}},"apple":{"type":"object","properties":{"has":{"type":"string"}}},"bukalapak":{"type":"object","properties":{"has":{"type":"string"}}},"facebook":{"type":"object","properties":{"has":{"type":"string"}}},"flipkart":{"type":"object","properties":{"has":{"type":"string"}}},"google":{"type":"object","properties":{"has":{"type":"string"}}},"instagram":{"type":"object","properties":{"has":{"type":"string"}}},"linkedin":{"type":"object","properties":{"has":{"type":"string"}}},"snapchat":{"type":"object","properties":{"has":{"type":"string"}}},"telegram":{"type":"object","properties":{"has":{"type":"string"}}},"viber":{"type":"object","properties":{"has":{"type":"string"}}},"whatsapp":{"type":"object","properties":{"has":{"type":"string"},"is_business":{"type":"string"}}},"x":{"type":"object","properties":{"has":{"type":"string"}}}}}}}}}}},"401":{"description":"Unauthorized","content":{"text/plain":{}}}},"parameters":[{"name":"X-API-KEY","in":"header","required":true,"description":"API key","schema":{"type":"string","format":"password","default":""}}]}}}}
```


# Contact Intelligence

## Contact intelligence

> \*\*Introduction\*\*\
> \
> Contact intelligence is a single enterprise endpoint that combines a real-time (HLR) query with a database fallback. For every MSISDN you submit it returns the number's country, current and original network, portability status and — when a live query succeeds — its real-time availability and GSM-level diagnostic.\
> \
> Send a \`POST\` request with a JSON body containing the MSISDNs to validate — the same payload used by the other Contact intelligence lookups, so many numbers can be validated in one call. The endpoint is served from \`<https://cleansing-api.bind.hr\\`.\\>
> \
> \*\*Request\*\*\
> \
> Authenticate with your enterprise API key in the \`X-API-KEY\` header and send a JSON body. Provide numbers in \*\*one\*\* of two mutually exclusive forms — a simple \`msisdn\` array, or a \`records\` array where each entry carries its own \`metadata\` and optional \`country\_iso\`. A maximum of 100 numbers can be validated per request; a request that mixes \`msisdn\` and \`records\` is rejected with response code 6.\
> \
> \| Field | Type | Required | Description |\
> \| --- | --- | --- | --- |\
> \| \`msisdn\` | string\[] | conditional | One or more MSISDNs to validate. Provide either \`msisdn\` or \`records\`, not both. |\
> \| \`records\` | object\[] | conditional | Records to validate. Provide either \`msisdn\` or \`records\`, not both. A record is only processed when it contains both \`msisdn\` and \`metadata\`. |\
> \| \`records\[].msisdn\` | string | yes | The MSISDN for this record. |\
> \| \`records\[].metadata\` | string | yes | Client reference echoed back on this number's result; records missing it are ignored. |\
> \| \`records\[].country\_iso\` | string | no | ISO 3166-1 alpha-2 country code for this number; falls back to the top-level \`country\_iso\`. |\
> \| \`country\_iso\` | string | no | Default ISO 3166-1 alpha-2 country code applied to every submitted number. |\
> \| \`metadata\` | string | no | Client reference echoed back on every result (for the \`msisdn\` array form). |\
> \| \`callback\_url\` | string (uri) | no | An optional URL to receive an asynchronous callback with the results. When set, the endpoint returns \`202\` with an \`id\` and POSTs the results to this URL when ready. |\
> \
> \*\*Response object\*\*\
> \
> The endpoint returns a JSON array with one object per submitted MSISDN. Each object contains:\
> \
> \- \`date\` — time when the request was executed (ISO 8601)\
> \- \`msisdn\` — the number as submitted\
> \- \`normalizedMsisdn\` — the number in normalized form\
> \- \`country\` — \`ISO2\`, \`countryDialCode\`, \`mcc\`, \`name\`\
> \- \`number\` — \`type\` (e.g. \`Mobile\`)\
> \- \`currentNetwork\` — \`mnc\`, \`name\`: the network the number currently belongs to\
> \- \`originalNetwork\` — \`mnc\`, \`name\`: the network the number was originally issued on\
> \- \`ported\` — \`true\` when the current network differs from the original network\
> \- \`availability\` — high-level reachability summary (see below)\
> \- \`diagnostic\` — GSM-level detail (see below)\
> \- \`source\` — \`type\`: how the result was resolved (see below)\
> \- \`cost\` — the price for this lookup\
> \- \`response\` — the result code (see below)\
> \
> \*\*Live vs. Database results\*\*\
> \
> \`source.type\` tells you how the result was resolved and how much of it you can rely on:\
> \
> \- \*\*\`Live\`\*\* — the number was queried in real time. \`diagnostic.gsmErrorAvailable\` is \`true\` and \`diagnostic.gsmError\` carries the GSM error code returned by the network, which drives the \`availability\` fields.\
> \- \*\*\`Database\`\*\* — live reachability could not be checked, so the result was resolved from database information only (format, country, network and portability). \`diagnostic.gsmError\` is \`null\`, \`diagnostic.gsmErrorAvailable\` is \`false\`, and \`availability.status\` / \`availability.condition\` are \`Unknown\`.\
> \
> \*\*\`availability\` object\*\*\
> \
> Derived from the GSM error code (see the table below):\
> \
> \- \`status\` — \`Available\`, \`Unavailable\`, \`Uncertain\` or \`Unknown\`\
> \- \`condition\` — \`Active\`, \`Permanent\`, \`Temporary\` or \`Unknown\`\
> \- \`reason\` — short human-readable explanation\
> \
> \*\*\`diagnostic\` object\*\*\
> \
> \- \`gsmError\` — the GSM error code (integer), or \`null\` for database-sourced results\
> \- \`gsmErrorAvailable\` — whether a live GSM error code is available\
> \- \`gsmErrorName\` — the symbolic name of the code (e.g. \`REACHABLE\`, \`ABSENT\_SUBSCRIBER\`), or \`null\`\
> \- \`gsmErrorDescription\` — a plain-language description of the code\
> \
> \*\*\`response\` values\*\*\
> \
> \| Value | Description | Action |\
> \|------:|-------------|--------|\
> \| 0 | Success | ✈️ |\
> \| 1 | General error | Repeating the request won't yield a different result |\
> \| 2 | Pricing not set | Contact <procurement@bind.hr> |\
> \| 3 | Out of balance | Contact <procurement@bind.hr> |\
> \| 4 | Throttled | Contact <procurement@bind.hr> |\
> \| 5 | Invalid number | Number length not valid |\
> \| 6 | Not resolved | Number cannot be resolved due to missing coverage |\
> \| 7 | Timeout | Number cannot be resolved due to timeout |\
> \| 8 | Missing permissions | Contact <procurement@bind.hr> |\
> \
> \*\*GSM error codes\*\*\
> \
> \`diagnostic.gsmError\` is populated for \`Live\` results and drives the \`availability\` fields as follows:\
> \
> \| Code | Name | Status | Condition | Reason | Description |\
> \| ---: | --- | --- | --- | --- | --- |\
> \| 0 | REACHABLE | Available | Active | Number is reachable. | The number appears to be active and reachable on the mobile network. |\
> \| 1 | UNKNOWN\_SUBSCRIBER | Unavailable | Permanent | Number is unknown. | The number is not recognized by the mobile network. It is likely inactive, disconnected, or not assigned. |\
> \| 5 | UNIDENTIFIED\_SUBSCRIBER | Unavailable | Permanent | Subscriber could not be identified. | The network could not identify the subscriber. The number is likely not valid or not active on the network. |\
> \| 9 | ILLEGAL\_SUBSCRIBER | Unavailable | Permanent | Subscriber is not allowed on the network. | The subscriber is rejected by the network. This usually indicates a blocked, invalid, or unauthorized subscription. |\
> \| 11 | TELESERVICE\_NOT\_PROVISIONED | Unavailable | Permanent | Messaging service is not enabled. | The number may exist, but the requested mobile service is not enabled for this subscriber. |\
> \| 13 | CALL\_BARRED | Unavailable | Temporary | Service is barred. | The number may exist, but the requested service is currently blocked or restricted by the operator. |\
> \| 21 | FACILITY\_NOT\_SUPPORTED | Uncertain | Unknown | Requested service is not supported. | The network does not support the requested service or lookup type, so the subscriber status cannot be confirmed. |\
> \| 27 | ABSENT\_SUBSCRIBER | Unavailable | Temporary | Subscriber is temporarily unreachable. | The number appears to exist, but the subscriber is currently not reachable on the network. |\
> \| 31 | SUBSCRIBER\_BUSY\_FOR\_MT\_SMS | Unavailable | Temporary | Subscriber is temporarily busy. | The number appears to exist, but the subscriber is temporarily busy or cannot receive the service at this moment. |\
> \| 32 | DELIVERY\_FAILURE | Uncertain | Unknown | Network returned an inconclusive failure. | The network returned a generic delivery failure. The final subscriber status cannot be reliably determined. |\
> \| 34 | SYSTEM\_FAILURE | Uncertain | Unknown | Network system failure. | The network or lookup provider returned a system failure. The subscriber status could not be confirmed. |\
> \| 36 | UNEXPECTED\_DATA\_VALUE | Uncertain | Unknown | Unexpected network response. | The network returned an unexpected value, so the subscriber status could not be reliably interpreted. |\
> \| 37 | MEMORY\_CAPACITY\_EXCEEDED | Unavailable | Temporary | Device memory may be full. | The number appears to exist, but the device or network reports that message storage capacity has been exceeded. |\
> \| 38 | PREFIX\_NOT\_RESOLVED | Unknown | Unknown | Number prefix could not be resolved. | The number prefix could not be matched to a valid country or network. Network and subscriber status are unknown. |\
> \| 39 | IMSI\_BLACKLISTED | Unavailable | Permanent | Subscriber identity is blacklisted. | The subscriber identity is blocked or blacklisted. The number should not be treated as reachable. |\
> \| 40 | DEST\_ADDRESS\_BLACKLISTED | Unavailable | Permanent | Destination number is blacklisted. | The destination number is blocked or blacklisted and should not be contacted. |\
> \| 41 | TIME\_OUT | Uncertain | Unknown | Lookup timed out. | The lookup did not complete within the expected time. The subscriber status could not be confirmed. |\
> \| 43 | INVALID\_ORIGINATOR\_ADDRESS | Uncertain | Unknown | Sender address was rejected. | The lookup or message was rejected because the sender/originator address was invalid. This does not reliably confirm the destination number status. |\
> \| 100 | GENERAL\_ERROR | Uncertain | Unknown | General processing error. | A general error occurred during processing. The subscriber status could not be confirmed. |\
> \| 200 | EQUIPMENT\_PROTOCOL\_ERROR | Uncertain | Unknown | Network protocol error. | A technical protocol error occurred between network systems. The subscriber status could not be confirmed. |\
> \| 201 | UNKNOWN\_MSC | Uncertain | Unknown | Serving network node is unknown. | The network could not identify the serving mobile switching node. The subscriber status could not be confirmed. |\
> \| 202 | CONGESTION\_ERROR | Uncertain | Temporary | Network congestion. | The network is congested or temporarily overloaded. The lookup should be retried later. |\
> \| 203 | PARAMETER\_MISSMATCH | Uncertain | Unknown | Request parameter mismatch. | The request contained parameters that did not match expected network values. The subscriber status could not be confirmed. |\
> \| 204 | INITIATING\_RELEASE | Uncertain | Unknown | Network released the request. | The network released the request before a clear subscriber status was returned. |\
> \| 205 | POTENTIAL\_VERSION\_INCOMPATIBILITY | Uncertain | Unknown | Network compatibility issue. | A compatibility issue occurred between network systems. The subscriber status could not be confirmed. |\
> \| 206 | REMOTE\_NODE\_NOT\_REACHABLE | Uncertain | Temporary | Remote network node is not reachable. | A required network node could not be reached. The lookup may succeed if retried later. |\
> \| 207 | MTP\_FAILURE | Uncertain | Temporary | Network transport failure. | A signalling transport failure occurred in the network. The lookup may succeed if retried later. |\
> \| 208 | NETWORK\_CONGESTION | Uncertain | Temporary | Network congestion. | The network is temporarily congested. The lookup should be retried later. |\
> \| 209 | SIGNALLING\_FAILURE | Uncertain | Temporary | Network signalling failure. | A signalling failure occurred in the mobile network. The lookup may succeed if retried later. |\
> \| 210 | ABNORMAL\_MAP\_DIALOG | Uncertain | Unknown | Abnormal network dialogue. | The network session ended abnormally, so the subscriber status could not be confirmed. |\
> \| 211 | INVALID\_PDU\_FORMAT | Uncertain | Unknown | Invalid network message format. | The network rejected the request format. The subscriber status could not be confirmed. |\
> \| 300 | ABORTED\_RETRY | Uncertain | Temporary | Lookup was aborted and should be retried. | The lookup was aborted before a final result was received. A retry may return a clearer result. |\
> \| 301 | VALIDITY\_PERIOD\_EXPIRED | Uncertain | Temporary | Request validity expired. | The request expired before a final network result was received. A retry may be required. |\
> \
> \> The \`DATABASE\_SOURCE\` code (\`9999\`) is never returned as a \`gsmError\` value — for database-sourced results \`gsmError\` is \`null\`. Its description (\_"Database source does not provide live reachability status."\_) is what surfaces in \`availability\` and \`diagnostic\` when \`source.type\` is \`Database\`.

```json
{"openapi":"3.1.0","info":{"title":"Contact intelligence API","version":"1.0"},"servers":[{"url":"https://cleansing-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}},"schemas":{"ContactIntelligenceRequest":{"type":"object","description":"Submit either a `msisdn` array **or** a `records` array — not both (a mixed request is rejected with response code 6). A maximum of 100 numbers can be validated per request.","properties":{"msisdn":{"type":"array","items":{"type":"string"},"maxItems":100,"description":"A list of MSISDNs to validate. Mutually exclusive with `records`."},"records":{"type":"array","items":{"$ref":"#/components/schemas/ContactIntelligenceRecord"},"maxItems":100,"description":"A list of records to validate, each carrying its own `metadata` and optional `country_iso`. Mutually exclusive with `msisdn`. A record is only processed when it contains both `msisdn` and `metadata`."},"country_iso":{"type":"string","description":"Optional default ISO 3166-1 alpha-2 country code (e.g. `HR`) applied to every submitted number. For `records`, a record's own `country_iso` takes precedence over this value."},"metadata":{"type":"string","description":"Optional client reference echoed back on every result. Applies to the `msisdn` array form; for `records` use the per-record `metadata` field instead."},"callback_url":{"type":"string","format":"uri","description":"Optional URL to receive an asynchronous callback with the results. When provided, the endpoint responds with `202` and `{ \"id\": \"<uuid>\" }`, then POSTs `{ \"id\": \"<uuid>\", \"data\": [ ... ] }` to this URL once processing completes."}}},"ContactIntelligenceRecord":{"type":"object","required":["msisdn","metadata"],"properties":{"msisdn":{"type":"string","description":"The MSISDN to validate."},"metadata":{"type":"string","description":"Client reference echoed back on this number's result. Required — records missing `msisdn` or `metadata` are ignored."},"country_iso":{"type":"string","description":"Optional ISO 3166-1 alpha-2 country code for this number (e.g. `HR`). Falls back to the top-level `country_iso` when omitted."}}}}},"paths":{"/enterprise/contact-intelligence":{"post":{"summary":"Contact intelligence","description":"**Introduction**\n\nContact intelligence is a single enterprise endpoint that combines a real-time (HLR) query with a database fallback. For every MSISDN you submit it returns the number's country, current and original network, portability status and — when a live query succeeds — its real-time availability and GSM-level diagnostic.\n\nSend a `POST` request with a JSON body containing the MSISDNs to validate — the same payload used by the other Contact intelligence lookups, so many numbers can be validated in one call. The endpoint is served from `https://cleansing-api.bind.hr`.\n\n**Request**\n\nAuthenticate with your enterprise API key in the `X-API-KEY` header and send a JSON body. Provide numbers in **one** of two mutually exclusive forms — a simple `msisdn` array, or a `records` array where each entry carries its own `metadata` and optional `country_iso`. A maximum of 100 numbers can be validated per request; a request that mixes `msisdn` and `records` is rejected with response code 6.\n\n| Field | Type | Required | Description |\n| --- | --- | --- | --- |\n| `msisdn` | string[] | conditional | One or more MSISDNs to validate. Provide either `msisdn` or `records`, not both. |\n| `records` | object[] | conditional | Records to validate. Provide either `msisdn` or `records`, not both. A record is only processed when it contains both `msisdn` and `metadata`. |\n| `records[].msisdn` | string | yes | The MSISDN for this record. |\n| `records[].metadata` | string | yes | Client reference echoed back on this number's result; records missing it are ignored. |\n| `records[].country_iso` | string | no | ISO 3166-1 alpha-2 country code for this number; falls back to the top-level `country_iso`. |\n| `country_iso` | string | no | Default ISO 3166-1 alpha-2 country code applied to every submitted number. |\n| `metadata` | string | no | Client reference echoed back on every result (for the `msisdn` array form). |\n| `callback_url` | string (uri) | no | An optional URL to receive an asynchronous callback with the results. When set, the endpoint returns `202` with an `id` and POSTs the results to this URL when ready. |\n\n**Response object**\n\nThe endpoint returns a JSON array with one object per submitted MSISDN. Each object contains:\n\n- `date` — time when the request was executed (ISO 8601)\n- `msisdn` — the number as submitted\n- `normalizedMsisdn` — the number in normalized form\n- `country` — `ISO2`, `countryDialCode`, `mcc`, `name`\n- `number` — `type` (e.g. `Mobile`)\n- `currentNetwork` — `mnc`, `name`: the network the number currently belongs to\n- `originalNetwork` — `mnc`, `name`: the network the number was originally issued on\n- `ported` — `true` when the current network differs from the original network\n- `availability` — high-level reachability summary (see below)\n- `diagnostic` — GSM-level detail (see below)\n- `source` — `type`: how the result was resolved (see below)\n- `cost` — the price for this lookup\n- `response` — the result code (see below)\n\n**Live vs. Database results**\n\n`source.type` tells you how the result was resolved and how much of it you can rely on:\n\n- **`Live`** — the number was queried in real time. `diagnostic.gsmErrorAvailable` is `true` and `diagnostic.gsmError` carries the GSM error code returned by the network, which drives the `availability` fields.\n- **`Database`** — live reachability could not be checked, so the result was resolved from database information only (format, country, network and portability). `diagnostic.gsmError` is `null`, `diagnostic.gsmErrorAvailable` is `false`, and `availability.status` / `availability.condition` are `Unknown`.\n\n**`availability` object**\n\nDerived from the GSM error code (see the table below):\n\n- `status` — `Available`, `Unavailable`, `Uncertain` or `Unknown`\n- `condition` — `Active`, `Permanent`, `Temporary` or `Unknown`\n- `reason` — short human-readable explanation\n\n**`diagnostic` object**\n\n- `gsmError` — the GSM error code (integer), or `null` for database-sourced results\n- `gsmErrorAvailable` — whether a live GSM error code is available\n- `gsmErrorName` — the symbolic name of the code (e.g. `REACHABLE`, `ABSENT_SUBSCRIBER`), or `null`\n- `gsmErrorDescription` — a plain-language description of the code\n\n**`response` values**\n\n| Value | Description | Action |\n|------:|-------------|--------|\n| 0 | Success | ✈️ |\n| 1 | General error | Repeating the request won't yield a different result |\n| 2 | Pricing not set | Contact procurement@bind.hr |\n| 3 | Out of balance | Contact procurement@bind.hr |\n| 4 | Throttled | Contact procurement@bind.hr |\n| 5 | Invalid number | Number length not valid |\n| 6 | Not resolved | Number cannot be resolved due to missing coverage |\n| 7 | Timeout | Number cannot be resolved due to timeout |\n| 8 | Missing permissions | Contact procurement@bind.hr |\n\n**GSM error codes**\n\n`diagnostic.gsmError` is populated for `Live` results and drives the `availability` fields as follows:\n\n| Code | Name | Status | Condition | Reason | Description |\n| ---: | --- | --- | --- | --- | --- |\n| 0 | REACHABLE | Available | Active | Number is reachable. | The number appears to be active and reachable on the mobile network. |\n| 1 | UNKNOWN_SUBSCRIBER | Unavailable | Permanent | Number is unknown. | The number is not recognized by the mobile network. It is likely inactive, disconnected, or not assigned. |\n| 5 | UNIDENTIFIED_SUBSCRIBER | Unavailable | Permanent | Subscriber could not be identified. | The network could not identify the subscriber. The number is likely not valid or not active on the network. |\n| 9 | ILLEGAL_SUBSCRIBER | Unavailable | Permanent | Subscriber is not allowed on the network. | The subscriber is rejected by the network. This usually indicates a blocked, invalid, or unauthorized subscription. |\n| 11 | TELESERVICE_NOT_PROVISIONED | Unavailable | Permanent | Messaging service is not enabled. | The number may exist, but the requested mobile service is not enabled for this subscriber. |\n| 13 | CALL_BARRED | Unavailable | Temporary | Service is barred. | The number may exist, but the requested service is currently blocked or restricted by the operator. |\n| 21 | FACILITY_NOT_SUPPORTED | Uncertain | Unknown | Requested service is not supported. | The network does not support the requested service or lookup type, so the subscriber status cannot be confirmed. |\n| 27 | ABSENT_SUBSCRIBER | Unavailable | Temporary | Subscriber is temporarily unreachable. | The number appears to exist, but the subscriber is currently not reachable on the network. |\n| 31 | SUBSCRIBER_BUSY_FOR_MT_SMS | Unavailable | Temporary | Subscriber is temporarily busy. | The number appears to exist, but the subscriber is temporarily busy or cannot receive the service at this moment. |\n| 32 | DELIVERY_FAILURE | Uncertain | Unknown | Network returned an inconclusive failure. | The network returned a generic delivery failure. The final subscriber status cannot be reliably determined. |\n| 34 | SYSTEM_FAILURE | Uncertain | Unknown | Network system failure. | The network or lookup provider returned a system failure. The subscriber status could not be confirmed. |\n| 36 | UNEXPECTED_DATA_VALUE | Uncertain | Unknown | Unexpected network response. | The network returned an unexpected value, so the subscriber status could not be reliably interpreted. |\n| 37 | MEMORY_CAPACITY_EXCEEDED | Unavailable | Temporary | Device memory may be full. | The number appears to exist, but the device or network reports that message storage capacity has been exceeded. |\n| 38 | PREFIX_NOT_RESOLVED | Unknown | Unknown | Number prefix could not be resolved. | The number prefix could not be matched to a valid country or network. Network and subscriber status are unknown. |\n| 39 | IMSI_BLACKLISTED | Unavailable | Permanent | Subscriber identity is blacklisted. | The subscriber identity is blocked or blacklisted. The number should not be treated as reachable. |\n| 40 | DEST_ADDRESS_BLACKLISTED | Unavailable | Permanent | Destination number is blacklisted. | The destination number is blocked or blacklisted and should not be contacted. |\n| 41 | TIME_OUT | Uncertain | Unknown | Lookup timed out. | The lookup did not complete within the expected time. The subscriber status could not be confirmed. |\n| 43 | INVALID_ORIGINATOR_ADDRESS | Uncertain | Unknown | Sender address was rejected. | The lookup or message was rejected because the sender/originator address was invalid. This does not reliably confirm the destination number status. |\n| 100 | GENERAL_ERROR | Uncertain | Unknown | General processing error. | A general error occurred during processing. The subscriber status could not be confirmed. |\n| 200 | EQUIPMENT_PROTOCOL_ERROR | Uncertain | Unknown | Network protocol error. | A technical protocol error occurred between network systems. The subscriber status could not be confirmed. |\n| 201 | UNKNOWN_MSC | Uncertain | Unknown | Serving network node is unknown. | The network could not identify the serving mobile switching node. The subscriber status could not be confirmed. |\n| 202 | CONGESTION_ERROR | Uncertain | Temporary | Network congestion. | The network is congested or temporarily overloaded. The lookup should be retried later. |\n| 203 | PARAMETER_MISSMATCH | Uncertain | Unknown | Request parameter mismatch. | The request contained parameters that did not match expected network values. The subscriber status could not be confirmed. |\n| 204 | INITIATING_RELEASE | Uncertain | Unknown | Network released the request. | The network released the request before a clear subscriber status was returned. |\n| 205 | POTENTIAL_VERSION_INCOMPATIBILITY | Uncertain | Unknown | Network compatibility issue. | A compatibility issue occurred between network systems. The subscriber status could not be confirmed. |\n| 206 | REMOTE_NODE_NOT_REACHABLE | Uncertain | Temporary | Remote network node is not reachable. | A required network node could not be reached. The lookup may succeed if retried later. |\n| 207 | MTP_FAILURE | Uncertain | Temporary | Network transport failure. | A signalling transport failure occurred in the network. The lookup may succeed if retried later. |\n| 208 | NETWORK_CONGESTION | Uncertain | Temporary | Network congestion. | The network is temporarily congested. The lookup should be retried later. |\n| 209 | SIGNALLING_FAILURE | Uncertain | Temporary | Network signalling failure. | A signalling failure occurred in the mobile network. The lookup may succeed if retried later. |\n| 210 | ABNORMAL_MAP_DIALOG | Uncertain | Unknown | Abnormal network dialogue. | The network session ended abnormally, so the subscriber status could not be confirmed. |\n| 211 | INVALID_PDU_FORMAT | Uncertain | Unknown | Invalid network message format. | The network rejected the request format. The subscriber status could not be confirmed. |\n| 300 | ABORTED_RETRY | Uncertain | Temporary | Lookup was aborted and should be retried. | The lookup was aborted before a final result was received. A retry may return a clearer result. |\n| 301 | VALIDITY_PERIOD_EXPIRED | Uncertain | Temporary | Request validity expired. | The request expired before a final network result was received. A retry may be required. |\n\n> The `DATABASE_SOURCE` code (`9999`) is never returned as a `gsmError` value — for database-sourced results `gsmError` is `null`. Its description (_\"Database source does not provide live reachability status.\"_) is what surfaces in `availability` and `diagnostic` when `source.type` is `Database`.","operationId":"one-lookup","tags":["Contact intelligence"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactIntelligenceRequest"}}}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["date","msisdn","response"],"properties":{"date":{"type":"string"},"msisdn":{"type":"string"},"normalizedMsisdn":{"type":"string"},"metadata":{"type":"string","description":"The client reference supplied for this number (top-level `metadata` for the `msisdn` form, or the per-record `metadata`). Only present when metadata was supplied in the request."},"cost":{"type":"number"},"response":{"type":"integer"},"ported":{"type":"boolean"},"country":{"type":"object","properties":{"ISO2":{"type":"string"},"countryDialCode":{"type":"string"},"mcc":{"type":"string"},"name":{"type":"string"}}},"number":{"type":"object","properties":{"type":{"type":"string"}}},"currentNetwork":{"type":"object","properties":{"mnc":{"type":"string"},"name":{"type":"string"}}},"originalNetwork":{"type":"object","properties":{"mnc":{"type":"string"},"name":{"type":"string"}}},"source":{"type":"object","properties":{"type":{"type":"string"}}},"availability":{"type":"object","properties":{"status":{"type":"string"},"condition":{"type":"string"},"reason":{"type":"string"}}},"diagnostic":{"type":"object","properties":{"gsmError":{"type":["integer","null"]},"gsmErrorAvailable":{"type":"boolean"},"gsmErrorName":{"type":["string","null"]},"gsmErrorDescription":{"type":"string"}}}}}}}}},"202":{"description":"Accepted — the request is being processed asynchronously. Returned only when `callback_url` is supplied; the results are POSTed to that URL as `{ \"id\": \"<uuid>\", \"data\": [ ... ] }` once ready.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Identifier for this asynchronous request; echoed back in the callback payload."}}}}}},"401":{"description":"401","content":{"text/plain":{}}},"500":{"description":"500","content":{"text/plain":{}}}},"deprecated":false}}}}
```


# Models

## The MsisdnRequest object

```json
{"openapi":"3.1.0","info":{"title":"Contact intelligence API","version":"1.0"},"components":{"schemas":{"MsisdnRequest":{"type":"object","required":["msisdn"],"properties":{"msisdn":{"type":"array","items":{"type":"string"},"description":"A list of MSISDNs to look up."},"callback_url":{"type":"string","format":"uri","description":"An optional URL to receive a callback with the results."}}}}}}
```

## The ContactIntelligenceRecord object

```json
{"openapi":"3.1.0","info":{"title":"Contact intelligence API","version":"1.0"},"components":{"schemas":{"ContactIntelligenceRecord":{"type":"object","required":["msisdn","metadata"],"properties":{"msisdn":{"type":"string","description":"The MSISDN to validate."},"metadata":{"type":"string","description":"Client reference echoed back on this number's result. Required — records missing `msisdn` or `metadata` are ignored."},"country_iso":{"type":"string","description":"Optional ISO 3166-1 alpha-2 country code for this number (e.g. `HR`). Falls back to the top-level `country_iso` when omitted."}}}}}}
```

## The ContactIntelligenceRequest object

```json
{"openapi":"3.1.0","info":{"title":"Contact intelligence API","version":"1.0"},"components":{"schemas":{"ContactIntelligenceRequest":{"type":"object","description":"Submit either a `msisdn` array **or** a `records` array — not both (a mixed request is rejected with response code 6). A maximum of 100 numbers can be validated per request.","properties":{"msisdn":{"type":"array","items":{"type":"string"},"maxItems":100,"description":"A list of MSISDNs to validate. Mutually exclusive with `records`."},"records":{"type":"array","items":{"$ref":"#/components/schemas/ContactIntelligenceRecord"},"maxItems":100,"description":"A list of records to validate, each carrying its own `metadata` and optional `country_iso`. Mutually exclusive with `msisdn`. A record is only processed when it contains both `msisdn` and `metadata`."},"country_iso":{"type":"string","description":"Optional default ISO 3166-1 alpha-2 country code (e.g. `HR`) applied to every submitted number. For `records`, a record's own `country_iso` takes precedence over this value."},"metadata":{"type":"string","description":"Optional client reference echoed back on every result. Applies to the `msisdn` array form; for `records` use the per-record `metadata` field instead."},"callback_url":{"type":"string","format":"uri","description":"Optional URL to receive an asynchronous callback with the results. When provided, the endpoint responds with `202` and `{ \"id\": \"<uuid>\" }`, then POSTs `{ \"id\": \"<uuid>\", \"data\": [ ... ] }` to this URL once processing completes."}}},"ContactIntelligenceRecord":{"type":"object","required":["msisdn","metadata"],"properties":{"msisdn":{"type":"string","description":"The MSISDN to validate."},"metadata":{"type":"string","description":"Client reference echoed back on this number's result. Required — records missing `msisdn` or `metadata` are ignored."},"country_iso":{"type":"string","description":"Optional ISO 3166-1 alpha-2 country code for this number (e.g. `HR`). Falls back to the top-level `country_iso` when omitted."}}}}}}
```


# Realtime Lookup

## Realtime Lookup

> \*\*Introduction\*\*\
> \
> Real-time lookup APIs allow you to discover live information for a provided number.\
> \
> By using the real-time lookup APIs you ensure the number you are querying is valid, along with information related to the number itself, such as the country and the network to which it belongs.\
> \
> Each response contains:\
> \
> \- \`date\` — time when the request was executed (ISO8601)\
> \- \`msisdn\` — the number for which the response has been returned\
> \- \`mcc\` — Mobile country code (\[learn more]\(<https://en.wikipedia.org/wiki/Mobile\\_country\\_code))\\>
> \- \`mnc\` — Mobile network code (\[learn more]\(<https://en.wikipedia.org/wiki/Mobile\\_country\\_code))\\>
> &#x20; \- the mobile network code to which the number currently belongs\
> \- \`omnc\` — Original network code\
> &#x20; \- returned in case the \`ported\` flag is \`true\`\
> \- \`originalNetwork\` (the network to which the number originally belonged)\
> &#x20; \- \`countryName\`\
> &#x20; \- \`countryPrefix\`\
> &#x20; \- \`networkName\`\
> \- \`portedNetwork\` (the network to which the number is currently ported)\
> &#x20; \- \`countryName\`\
> &#x20; \- \`countryPrefix\`\
> &#x20; \- \`networkName\`\
> \- \`ported\` — denotes whether the number has been ported\
> \- \`imsi\` — IMSI (\[learn more]\(<https://en.wikipedia.org/wiki/International\\_mobile\\_subscriber\\_identity))\\>
> \- \`gsmErrorCode\` — error code related to user availability (see below)\
> \- \`price\` — the price for this request\
> \- \`response\` — the result code (see below)\
> \
> \*\*Response values\*\*\
> \
> \| Value | Description | Action |\
> \|------:|-------------|--------|\
> \| 0 | Success | ✈️ |\
> \| 1 | General error | Repeating the request won't yield a different result |\
> \| 2 | Pricing not set | Contact <procurement@bind.hr> |\
> \| 3 | Out of balance | Contact <procurement@bind.hr> |\
> \| 4 | Throttled | Contact <procurement@bind.hr> |\
> \| 5 | Invalid number | Number length not valid |\
> \| 6 | Not resolved | Number cannot be resolved due to missing coverage |\
> \| 7 | Timeout | Number cannot be resolved due to timeout |\
> \| 8 | Missing permissions | Contact <procurement@bind.hr> |\
> \
> \*\*GSM error codes\*\*\
> \
> \| EC  | ERROR DESCRIPTION                 |\
> \| --- | --------------------------------- |\
> \| 0   | REACHABLE                         |\
> \| 1   | UNKNOWN\_SUBSCRIBER                |\
> \| 5   | UNIDENTIFIED\_SUBSCRIBER           |\
> \| 9   | ILLEGAL\_SUBSCRIBER                |\
> \| 11  | TELESERVICE\_NOT\_PROVISIONED       |\
> \| 13  | CALL\_BARRED                       |\
> \| 21  | FACILITY\_NOT\_SUPPORTED            |\
> \| 27  | ABSENT\_SUBSCRIBER                 |\
> \| 31  | SUBSCRIBER\_BUSY\_FOR\_MT\_SMS        |\
> \| 32  | DELIVERY\_FAILURE                  |\
> \| 34  | SYSTEM\_FAILURE                    |\
> \| 36  | UNEXPECTED\_DATA\_VALUE             |\
> \| 37  | MEMORY\_CAPACITY\_EXCEEDED          |\
> \| 38  | PREFIX\_NOT\_RESOLVED               |\
> \| 39  | IMSI\_BLACKLISTED                  |\
> \| 40  | DEST\_ADDRESS\_BLACKLISTED          |\
> \| 41  | TIME\_OUT                          |\
> \| 43  | INVALID\_ORIGINATOR\_ADDRESS        |\
> \| 100 | GENERAL\_ERROR                     |\
> \| 200 | EQUIPMENT\_PROTOCOL\_ERROR          |\
> \| 201 | UNKNOWN\_MSC                       |\
> \| 202 | CONGESTION\_ERROR                  |\
> \| 203 | PARAMETER\_MISSMATCH               |\
> \| 204 | INITIATING\_RELEASE                |\
> \| 205 | POTENTIAL\_VERSION\_INCOMPATIBILITY |\
> \| 206 | REMOTE\_NODE\_NOT\_REACHABLE         |\
> \| 207 | MTP\_FAILURE                       |\
> \| 208 | NETWORK\_CONGESTION                |\
> \| 209 | SIGNALLING\_FAILURE                |\
> \| 210 | ABNORMAL\_MAP\_DIALOG               |\
> \| 211 | INVALID\_PDU\_FORMAT                |\
> \| 300 | ABORTED\_RETRY                     |\
> \| 301 | VALIDITY\_PERIOD\_EXPIRED           |

```json
{"openapi":"3.1.0","info":{"title":"Number intelligence API","version":"1.0"},"servers":[{"url":"https://number-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}},"schemas":{"MsisdnRequest":{"type":"object","required":["msisdn"],"properties":{"msisdn":{"type":"array","items":{"type":"string"},"description":"A list of MSISDNs to look up."},"callback_url":{"type":"string","format":"uri","description":"An optional URL to receive a callback with the results."}}}}},"paths":{"/lookup/hlr":{"post":{"summary":"Realtime Lookup","description":"**Introduction**\n\nReal-time lookup APIs allow you to discover live information for a provided number.\n\nBy using the real-time lookup APIs you ensure the number you are querying is valid, along with information related to the number itself, such as the country and the network to which it belongs.\n\nEach response contains:\n\n- `date` — time when the request was executed (ISO8601)\n- `msisdn` — the number for which the response has been returned\n- `mcc` — Mobile country code ([learn more](https://en.wikipedia.org/wiki/Mobile_country_code))\n- `mnc` — Mobile network code ([learn more](https://en.wikipedia.org/wiki/Mobile_country_code))\n  - the mobile network code to which the number currently belongs\n- `omnc` — Original network code\n  - returned in case the `ported` flag is `true`\n- `originalNetwork` (the network to which the number originally belonged)\n  - `countryName`\n  - `countryPrefix`\n  - `networkName`\n- `portedNetwork` (the network to which the number is currently ported)\n  - `countryName`\n  - `countryPrefix`\n  - `networkName`\n- `ported` — denotes whether the number has been ported\n- `imsi` — IMSI ([learn more](https://en.wikipedia.org/wiki/International_mobile_subscriber_identity))\n- `gsmErrorCode` — error code related to user availability (see below)\n- `price` — the price for this request\n- `response` — the result code (see below)\n\n**Response values**\n\n| Value | Description | Action |\n|------:|-------------|--------|\n| 0 | Success | ✈️ |\n| 1 | General error | Repeating the request won't yield a different result |\n| 2 | Pricing not set | Contact procurement@bind.hr |\n| 3 | Out of balance | Contact procurement@bind.hr |\n| 4 | Throttled | Contact procurement@bind.hr |\n| 5 | Invalid number | Number length not valid |\n| 6 | Not resolved | Number cannot be resolved due to missing coverage |\n| 7 | Timeout | Number cannot be resolved due to timeout |\n| 8 | Missing permissions | Contact procurement@bind.hr |\n\n**GSM error codes**\n\n| EC  | ERROR DESCRIPTION                 |\n| --- | --------------------------------- |\n| 0   | REACHABLE                         |\n| 1   | UNKNOWN_SUBSCRIBER                |\n| 5   | UNIDENTIFIED_SUBSCRIBER           |\n| 9   | ILLEGAL_SUBSCRIBER                |\n| 11  | TELESERVICE_NOT_PROVISIONED       |\n| 13  | CALL_BARRED                       |\n| 21  | FACILITY_NOT_SUPPORTED            |\n| 27  | ABSENT_SUBSCRIBER                 |\n| 31  | SUBSCRIBER_BUSY_FOR_MT_SMS        |\n| 32  | DELIVERY_FAILURE                  |\n| 34  | SYSTEM_FAILURE                    |\n| 36  | UNEXPECTED_DATA_VALUE             |\n| 37  | MEMORY_CAPACITY_EXCEEDED          |\n| 38  | PREFIX_NOT_RESOLVED               |\n| 39  | IMSI_BLACKLISTED                  |\n| 40  | DEST_ADDRESS_BLACKLISTED          |\n| 41  | TIME_OUT                          |\n| 43  | INVALID_ORIGINATOR_ADDRESS        |\n| 100 | GENERAL_ERROR                     |\n| 200 | EQUIPMENT_PROTOCOL_ERROR          |\n| 201 | UNKNOWN_MSC                       |\n| 202 | CONGESTION_ERROR                  |\n| 203 | PARAMETER_MISSMATCH               |\n| 204 | INITIATING_RELEASE                |\n| 205 | POTENTIAL_VERSION_INCOMPATIBILITY |\n| 206 | REMOTE_NODE_NOT_REACHABLE         |\n| 207 | MTP_FAILURE                       |\n| 208 | NETWORK_CONGESTION                |\n| 209 | SIGNALLING_FAILURE                |\n| 210 | ABNORMAL_MAP_DIALOG               |\n| 211 | INVALID_PDU_FORMAT                |\n| 300 | ABORTED_RETRY                     |\n| 301 | VALIDITY_PERIOD_EXPIRED           |","operationId":"resolve-live","tags":["Realtime Lookup"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MsisdnRequest"}}}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["date","msisdn","price","response"],"properties":{"date":{"type":"string"},"mcc":{"type":"string"},"mnc":{"type":"string"},"msisdn":{"type":"string"},"omnc":{"type":"string"},"originalNetwork":{"type":"object","properties":{"countryName":{"type":"string"},"countryPrefix":{"type":"string"},"networkName":{"type":"string"}}},"ported":{"type":"boolean"},"gsmErrorCode":{"type":"integer"},"portedNetwork":{"type":"object","properties":{"countryName":{"type":"string"},"countryPrefix":{"type":"string"},"networkName":{"type":"string"}}},"imsi":{"type":"string"},"price":{"type":"number"},"response":{"type":"integer"}}}}}}},"401":{"description":"401","content":{"text/plain":{}}},"500":{"description":"500","content":{"text/plain":{}}}},"deprecated":false}}}}
```


# Portability Lookup

## MNP lookup

> \*\*Introduction\*\*\
> \
> Mobile Number Portability (MNP) lookup APIs allow you to discover information about a provided number by directly querying mobile number portability databases.\
> \
> Each response contains:\
> \- \`date\` — time when the request was executed (ISO8601)\
> \- \`msisdn\` — the number for which the response has been returned\
> \- \`mcc\` — Mobile country code (\[learn more]\(<https://en.wikipedia.org/wiki/Mobile\\_country\\_code))\\>
> \- \`mnc\` — Mobile network code (\[learn more]\(<https://en.wikipedia.org/wiki/Mobile\\_country\\_code))\\>
> &#x20; \- the mobile network code to which the number currently belongs\
> \- \`omnc\` — Original network code\
> &#x20; \- returned in case the \`ported\` flag is \`true\`\
> \- \`originalNetwork\` (the network to which the number originally belonged)\
> &#x20; \- \`countryName\`\
> &#x20; \- \`countryPrefix\`\
> &#x20; \- \`networkName\`\
> \- \`portedNetwork\` (the network to which the number is currently ported)\
> &#x20; \- \`countryName\`\
> &#x20; \- \`countryPrefix\`\
> &#x20; \- \`networkName\`\
> \- \`ported\` — whether the number has been ported\
> \- \`price\` — the price for this request\
> \- \`response\` — the result code (see below)\
> \
> \*\*Response values\*\*\
> \
> \| Value | Description | Action |\
> \|------:|-------------|--------|\
> \| 0 | Success | ✈️ |\
> \| 1 | General error | Repeating the request won't yield a different result |\
> \| 2 | Pricing not set | Contact <procurement@bind.hr> |\
> \| 3 | Out of balance | Contact <procurement@bind.hr> |\
> \| 4 | Throttled | Contact <procurement@bind.hr> |\
> \| 5 | Invalid number | Number length not valid |\
> \| 6 | Not resolved | Number cannot be resolved due to missing coverage |\
> \| 7 | Timeout | Number cannot be resolved due to timeout |\
> \| 8 | Missing permissions | Contact <procurement@bind.hr> |

```json
{"openapi":"3.1.0","info":{"title":"Number intelligence API","version":"1.0"},"servers":[{"url":"https://number-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}},"schemas":{"MsisdnRequest":{"type":"object","required":["msisdn"],"properties":{"msisdn":{"type":"array","items":{"type":"string"},"description":"A list of MSISDNs to look up."},"callback_url":{"type":"string","format":"uri","description":"An optional URL to receive a callback with the results."}}}}},"paths":{"/lookup/mnp":{"post":{"summary":"MNP lookup","description":"**Introduction**\n\nMobile Number Portability (MNP) lookup APIs allow you to discover information about a provided number by directly querying mobile number portability databases.\n\nEach response contains:\n- `date` — time when the request was executed (ISO8601)\n- `msisdn` — the number for which the response has been returned\n- `mcc` — Mobile country code ([learn more](https://en.wikipedia.org/wiki/Mobile_country_code))\n- `mnc` — Mobile network code ([learn more](https://en.wikipedia.org/wiki/Mobile_country_code))\n  - the mobile network code to which the number currently belongs\n- `omnc` — Original network code\n  - returned in case the `ported` flag is `true`\n- `originalNetwork` (the network to which the number originally belonged)\n  - `countryName`\n  - `countryPrefix`\n  - `networkName`\n- `portedNetwork` (the network to which the number is currently ported)\n  - `countryName`\n  - `countryPrefix`\n  - `networkName`\n- `ported` — whether the number has been ported\n- `price` — the price for this request\n- `response` — the result code (see below)\n\n**Response values**\n\n| Value | Description | Action |\n|------:|-------------|--------|\n| 0 | Success | ✈️ |\n| 1 | General error | Repeating the request won't yield a different result |\n| 2 | Pricing not set | Contact procurement@bind.hr |\n| 3 | Out of balance | Contact procurement@bind.hr |\n| 4 | Throttled | Contact procurement@bind.hr |\n| 5 | Invalid number | Number length not valid |\n| 6 | Not resolved | Number cannot be resolved due to missing coverage |\n| 7 | Timeout | Number cannot be resolved due to timeout |\n| 8 | Missing permissions | Contact procurement@bind.hr |","operationId":"mnpdb","tags":["Portability Lookup"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MsisdnRequest"}}}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["date","msisdn","price","response"],"properties":{"date":{"type":"string"},"mcc":{"type":"string"},"mnc":{"type":"string"},"msisdn":{"type":"string"},"omnc":{"type":"string"},"originalNetwork":{"type":"object","properties":{"countryName":{"type":"string"},"countryPrefix":{"type":"string"},"networkName":{"type":"string"}}},"ported":{"type":"boolean"},"portedNetwork":{"type":"object","properties":{"countryName":{"type":"string"},"countryPrefix":{"type":"string"},"networkName":{"type":"string"}}},"price":{"type":"number"},"response":{"type":"integer"}}}}}}},"401":{"description":"401","content":{"text/plain":{}}},"500":{"description":"500","content":{"text/plain":{}}}},"deprecated":false}}}}
```


# One Lookup

## OneLookup

> \*\*Introduction\*\*\
> \
> OneLookup is a single endpoint that combines a real-time (HLR) query with a database fallback, letting you validate one or many numbers in a single call.\
> \
> For each MSISDN you submit it returns the number's country and network information, portability status and — when a live query succeeds — its real-time availability via a GSM error code.\
> \
> Each response contains:\
> \
> \- \`date\` — time when the request was executed (ISO8601)\
> \- \`msisdn\` — the number for which the response has been returned\
> \- \`live\` — whether the result was obtained from a live (real-time) query\
> \- \`numberType\` — the type of number (e.g. \`Mobile\`)\
> \- \`mcc\` — Mobile country code (\[learn more]\(<https://en.wikipedia.org/wiki/Mobile\\_country\\_code))\\>
> \- \`mnc\` — Mobile network code the number currently belongs to\
> \- \`omnc\` — Original network code (the network the number originally belonged to)\
> \- \`spid\` — Service provider ID of the current network\
> \- \`oSpid\` — Service provider ID of the original network\
> \- \`imsi\` — IMSI (\[learn more]\(<https://en.wikipedia.org/wiki/International\\_mobile\\_subscriber\\_identity>)); returned when available\
> \- \`originalNetwork\` (the network to which the number originally belonged)\
> &#x20; \- \`countryName\`\
> &#x20; \- \`countryPrefix\`\
> &#x20; \- \`networkName\`\
> \- \`portedNetwork\` (the network to which the number is currently ported); returned when \`ported\` is \`true\`\
> &#x20; \- \`countryName\`\
> &#x20; \- \`countryPrefix\`\
> &#x20; \- \`networkName\`\
> \- \`ported\` — denotes whether the number has been ported\
> \- \`gsmErrorCode\` — error code related to user availability (see below)\
> \- \`price\` — the price for this request\
> \- \`response\` — the result code (see below)\
> \
> \*\*Response values\*\*\
> \
> \| Value | Description | Action |\
> \|------:|-------------|--------|\
> \| 0 | Success | ✈️ |\
> \| 1 | General error | Repeating the request won't yield a different result |\
> \| 2 | Pricing not set | Contact <procurement@bind.hr> |\
> \| 3 | Out of balance | Contact <procurement@bind.hr> |\
> \| 4 | Throttled | Contact <procurement@bind.hr> |\
> \| 5 | Invalid number | Number length not valid |\
> \| 6 | Not resolved | Number cannot be resolved due to missing coverage |\
> \| 7 | Timeout | Number cannot be resolved due to timeout |\
> \| 8 | Missing permissions | Contact <procurement@bind.hr> |\
> \
> \*\*GSM error codes\*\*\
> \
> \| EC  | ERROR DESCRIPTION                 |\
> \| --- | --------------------------------- |\
> \| 0   | REACHABLE                         |\
> \| 1   | UNKNOWN\_SUBSCRIBER                |\
> \| 5   | UNIDENTIFIED\_SUBSCRIBER           |\
> \| 9   | ILLEGAL\_SUBSCRIBER                |\
> \| 11  | TELESERVICE\_NOT\_PROVISIONED       |\
> \| 13  | CALL\_BARRED                       |\
> \| 21  | FACILITY\_NOT\_SUPPORTED            |\
> \| 27  | ABSENT\_SUBSCRIBER                 |\
> \| 31  | SUBSCRIBER\_BUSY\_FOR\_MT\_SMS        |\
> \| 32  | DELIVERY\_FAILURE                  |\
> \| 34  | SYSTEM\_FAILURE                    |\
> \| 36  | UNEXPECTED\_DATA\_VALUE             |\
> \| 37  | MEMORY\_CAPACITY\_EXCEEDED          |\
> \| 38  | PREFIX\_NOT\_RESOLVED               |\
> \| 39  | IMSI\_BLACKLISTED                  |\
> \| 40  | DEST\_ADDRESS\_BLACKLISTED          |\
> \| 41  | TIME\_OUT                          |\
> \| 43  | INVALID\_ORIGINATOR\_ADDRESS        |\
> \| 100 | GENERAL\_ERROR                     |\
> \| 200 | EQUIPMENT\_PROTOCOL\_ERROR          |\
> \| 201 | UNKNOWN\_MSC                       |\
> \| 202 | CONGESTION\_ERROR                  |\
> \| 203 | PARAMETER\_MISSMATCH               |\
> \| 204 | INITIATING\_RELEASE                |\
> \| 205 | POTENTIAL\_VERSION\_INCOMPATIBILITY |\
> \| 206 | REMOTE\_NODE\_NOT\_REACHABLE         |\
> \| 207 | MTP\_FAILURE                       |\
> \| 208 | NETWORK\_CONGESTION                |\
> \| 209 | SIGNALLING\_FAILURE                |\
> \| 210 | ABNORMAL\_MAP\_DIALOG               |\
> \| 211 | INVALID\_PDU\_FORMAT                |\
> \| 300 | ABORTED\_RETRY                     |\
> \| 301 | VALIDITY\_PERIOD\_EXPIRED           |

```json
{"openapi":"3.1.0","info":{"title":"Number intelligence API","version":"1.0"},"servers":[{"url":"https://number-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}},"schemas":{"MsisdnRequest":{"type":"object","required":["msisdn"],"properties":{"msisdn":{"type":"array","items":{"type":"string"},"description":"A list of MSISDNs to look up."},"callback_url":{"type":"string","format":"uri","description":"An optional URL to receive a callback with the results."}}}}},"paths":{"/lookup/onelookup":{"post":{"summary":"OneLookup","description":"**Introduction**\n\nOneLookup is a single endpoint that combines a real-time (HLR) query with a database fallback, letting you validate one or many numbers in a single call.\n\nFor each MSISDN you submit it returns the number's country and network information, portability status and — when a live query succeeds — its real-time availability via a GSM error code.\n\nEach response contains:\n\n- `date` — time when the request was executed (ISO8601)\n- `msisdn` — the number for which the response has been returned\n- `live` — whether the result was obtained from a live (real-time) query\n- `numberType` — the type of number (e.g. `Mobile`)\n- `mcc` — Mobile country code ([learn more](https://en.wikipedia.org/wiki/Mobile_country_code))\n- `mnc` — Mobile network code the number currently belongs to\n- `omnc` — Original network code (the network the number originally belonged to)\n- `spid` — Service provider ID of the current network\n- `oSpid` — Service provider ID of the original network\n- `imsi` — IMSI ([learn more](https://en.wikipedia.org/wiki/International_mobile_subscriber_identity)); returned when available\n- `originalNetwork` (the network to which the number originally belonged)\n  - `countryName`\n  - `countryPrefix`\n  - `networkName`\n- `portedNetwork` (the network to which the number is currently ported); returned when `ported` is `true`\n  - `countryName`\n  - `countryPrefix`\n  - `networkName`\n- `ported` — denotes whether the number has been ported\n- `gsmErrorCode` — error code related to user availability (see below)\n- `price` — the price for this request\n- `response` — the result code (see below)\n\n**Response values**\n\n| Value | Description | Action |\n|------:|-------------|--------|\n| 0 | Success | ✈️ |\n| 1 | General error | Repeating the request won't yield a different result |\n| 2 | Pricing not set | Contact procurement@bind.hr |\n| 3 | Out of balance | Contact procurement@bind.hr |\n| 4 | Throttled | Contact procurement@bind.hr |\n| 5 | Invalid number | Number length not valid |\n| 6 | Not resolved | Number cannot be resolved due to missing coverage |\n| 7 | Timeout | Number cannot be resolved due to timeout |\n| 8 | Missing permissions | Contact procurement@bind.hr |\n\n**GSM error codes**\n\n| EC  | ERROR DESCRIPTION                 |\n| --- | --------------------------------- |\n| 0   | REACHABLE                         |\n| 1   | UNKNOWN_SUBSCRIBER                |\n| 5   | UNIDENTIFIED_SUBSCRIBER           |\n| 9   | ILLEGAL_SUBSCRIBER                |\n| 11  | TELESERVICE_NOT_PROVISIONED       |\n| 13  | CALL_BARRED                       |\n| 21  | FACILITY_NOT_SUPPORTED            |\n| 27  | ABSENT_SUBSCRIBER                 |\n| 31  | SUBSCRIBER_BUSY_FOR_MT_SMS        |\n| 32  | DELIVERY_FAILURE                  |\n| 34  | SYSTEM_FAILURE                    |\n| 36  | UNEXPECTED_DATA_VALUE             |\n| 37  | MEMORY_CAPACITY_EXCEEDED          |\n| 38  | PREFIX_NOT_RESOLVED               |\n| 39  | IMSI_BLACKLISTED                  |\n| 40  | DEST_ADDRESS_BLACKLISTED          |\n| 41  | TIME_OUT                          |\n| 43  | INVALID_ORIGINATOR_ADDRESS        |\n| 100 | GENERAL_ERROR                     |\n| 200 | EQUIPMENT_PROTOCOL_ERROR          |\n| 201 | UNKNOWN_MSC                       |\n| 202 | CONGESTION_ERROR                  |\n| 203 | PARAMETER_MISSMATCH               |\n| 204 | INITIATING_RELEASE                |\n| 205 | POTENTIAL_VERSION_INCOMPATIBILITY |\n| 206 | REMOTE_NODE_NOT_REACHABLE         |\n| 207 | MTP_FAILURE                       |\n| 208 | NETWORK_CONGESTION                |\n| 209 | SIGNALLING_FAILURE                |\n| 210 | ABNORMAL_MAP_DIALOG               |\n| 211 | INVALID_PDU_FORMAT                |\n| 300 | ABORTED_RETRY                     |\n| 301 | VALIDITY_PERIOD_EXPIRED           |","operationId":"one-lookup","tags":["OneLookup"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MsisdnRequest"}}}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["date","msisdn","price","response"],"properties":{"date":{"type":"string"},"msisdn":{"type":"string"},"live":{"type":"boolean"},"numberType":{"type":"string"},"mcc":{"type":"string"},"mnc":{"type":"string"},"omnc":{"type":"string"},"spid":{"type":"integer"},"oSpid":{"type":"integer"},"imsi":{"type":"string"},"originalNetwork":{"type":"object","properties":{"countryName":{"type":"string"},"countryPrefix":{"type":"string"},"networkName":{"type":"string"}}},"portedNetwork":{"type":"object","properties":{"countryName":{"type":"string"},"countryPrefix":{"type":"string"},"networkName":{"type":"string"}}},"ported":{"type":"boolean"},"gsmErrorCode":{"type":"integer"},"price":{"type":"number"},"response":{"type":"integer"}}}}}}},"401":{"description":"401","content":{"text/plain":{}}},"500":{"description":"500","content":{"text/plain":{}}}},"deprecated":false}}}}
```


# Models

## The MsisdnRequest object

```json
{"openapi":"3.1.0","info":{"title":"Number intelligence API","version":"1.0"},"components":{"schemas":{"MsisdnRequest":{"type":"object","required":["msisdn"],"properties":{"msisdn":{"type":"array","items":{"type":"string"},"description":"A list of MSISDNs to look up."},"callback_url":{"type":"string","format":"uri","description":"An optional URL to receive a callback with the results."}}}}}}
```


# Guidelines

## The Importance of Using SMS Templates

At Bind, ensuring the security and integrity of our messaging services is a top priority. To protect end-users from unsolicited messages, scams, and smishing attempts, we require the use of pre-approved SMS templates for all outgoing messages.

### Why Templates are Required

The primary reason for this policy is to create a safe and trustworthy messaging environment. By validating every template, we can significantly reduce the risk of malicious content reaching telephone numbers. This process helps us ensure that all communications sent through our platform are legitimate and expected by the recipient.

### The Template Approval Process

To maintain these high standards, all SMS templates must go through a validation process before they can be used:

1. **Submission:** Clients create and submit their SMS templates through our API
2. **Validation:** The Bind team carefully reviews each submitted template to ensure it complies with our security standards and does not contain any potentially harmful or unsolicited content.
3. **Approval Notification:** Once a template is approved, the client will receive an email notification confirming that the template is ready for use.

Only after a template has been successfully validated and approved can it be used to send messages to your audience. This ensures that every message sent from our platform is secure, compliant, and trustworthy.


# Template

## List

> Returns client-specific templates (optionally filtered by status) plus common approved templates.<br>

```json
{"openapi":"3.0.3","info":{"title":"SMS Template API","version":"1.0.0"},"servers":[{"url":"https://messaging-api.bind.hr","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-KEY","description":"API key header."}},"schemas":{}},"paths":{"/v1.0/sms/template":{"get":{"tags":["Template"],"summary":"List","description":"Returns client-specific templates (optionally filtered by status) plus common approved templates.\n","parameters":[{"in":"query","name":"status","schema":{"type":"string"},"required":false,"description":"Optional status filter (e.g. `approved`, `for_review`)."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListResponse"}}}},"401":{"description":"Unauthorized (missing/invalid API key)"},"500":{"description":"Internal server error"}}}}}}
```

## Create

> Create a new template.

```json
{"openapi":"3.0.3","info":{"title":"SMS Template API","version":"1.0.0"},"servers":[{"url":"https://messaging-api.bind.hr","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-KEY","description":"API key header."}},"schemas":{"SubmitRequest":{"type":"object","properties":{"name":{"type":"string"},"sender":{"type":"string","minLength":3,"maxLength":15},"content":{"type":"string","maxLength":1000}},"required":["name","sender","content"]},"SubmitResponse":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/TemplateBase"}},"required":["success","item"]},"TemplateBase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"sender":{"type":"string","description":"Sender ID. Numeric 4-15 digits or alphanumeric up to 11 chars (A-Z a-z 0-9 _ space)."},"content":{"type":"string"},"status":{"type":"string","description":"Template status (e.g., for_review, approved)."}},"required":["id","name","sender","content","status"]},"OperationError":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"}},"required":["success","error"]}}},"paths":{"/v1.0/sms/template":{"post":{"tags":["Template"],"summary":"Create","description":"Create a new template.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitRequest"}}}},"responses":{"200":{"description":"Created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationError"}}}},"401":{"description":"Unauthorized (missing/invalid API key)"},"500":{"description":"Failed to create","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationError"}}}}}}}}}
```

## Update

> Update an existing template.

```json
{"openapi":"3.0.3","info":{"title":"SMS Template API","version":"1.0.0"},"servers":[{"url":"https://messaging-api.bind.hr","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-KEY","description":"API key header."}},"schemas":{"SubmitRequest":{"type":"object","properties":{"name":{"type":"string"},"sender":{"type":"string","minLength":3,"maxLength":15},"content":{"type":"string","maxLength":1000}},"required":["name","sender","content"]},"SubmitResponse":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/TemplateBase"}},"required":["success","item"]},"TemplateBase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"sender":{"type":"string","description":"Sender ID. Numeric 4-15 digits or alphanumeric up to 11 chars (A-Z a-z 0-9 _ space)."},"content":{"type":"string"},"status":{"type":"string","description":"Template status (e.g., for_review, approved)."}},"required":["id","name","sender","content","status"]},"OperationError":{"type":"object","properties":{"success":{"type":"boolean"},"error":{"type":"string"}},"required":["success","error"]}}},"paths":{"/v1.0/sms/template/{id}":{"put":{"tags":["Template"],"summary":"Update","description":"Update an existing template.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Template id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitRequest"}}}},"responses":{"200":{"description":"Updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitResponse"}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationError"}}}},"401":{"description":"Unauthorized (missing/invalid API key)"},"404":{"description":"Template not found"},"500":{"description":"Failed to update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperationError"}}}}}}}}}
```

## DELETE /v1.0/sms/template/{id}

> Delete

```json
{"openapi":"3.0.3","info":{"title":"SMS Template API","version":"1.0.0"},"servers":[{"url":"https://messaging-api.bind.hr","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-KEY","description":"API key header."}},"schemas":{"DeleteResponse":{"type":"object","properties":{"success":{"type":"boolean"},"item":{"$ref":"#/components/schemas/TemplateBase"}},"required":["success","item"]},"TemplateBase":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"sender":{"type":"string","description":"Sender ID. Numeric 4-15 digits or alphanumeric up to 11 chars (A-Z a-z 0-9 _ space)."},"content":{"type":"string"},"status":{"type":"string","description":"Template status (e.g., for_review, approved)."}},"required":["id","name","sender","content","status"]}}},"paths":{"/v1.0/sms/template/{id}":{"delete":{"tags":["Template"],"summary":"Delete","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Template id"}],"responses":{"200":{"description":"Deleted (soft) successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"401":{"description":"Unauthorized (missing/invalid API key)"},"404":{"description":"Template not found / already deleted"},"500":{"description":"Failed to delete"}}}}}}
```


# Send Templated Message

## Send an SMS using a template

> Provide the destination number \`to\`, and optional \`callback\_url\`,\
> plus all template parameters under \`params\` as additional JSON fields (all string values).\
> Check the Templates API for fetching the template \`id\`.\
> \
> \## Callback request example (DLR - delivery notification)\
> \
> \### POST /\<callback\_url>\
> \
> \`\`\`json\
> {\
> &#x20; "error": "000",\
> &#x20; "from": "18888112345",\
> &#x20; "message\_id": "8bd71f49-6f42-4729-bf5e-ecf857747633",\
> &#x20; "status": "DELIVERED",\
> &#x20; "to": "16197012345",\
> &#x20; "type": "DLR"\
> }\
> \`\`\`\
> \
> Each request contains the following information:\
> \
> \* \`message\_id\` - the id of the message which has been returned following \`/send\`  request\
> \* \`from\` - the source address the message was sent from\
> \* \`to\` - the destination address which has received the message\
> \* \`status\`- the status of the message\
> &#x20; \* \`DELIVERED\` - Message has been delivered\
> &#x20; \* \`EXPIRED\` - Message wasn't delivered within the 48 hour period\
> &#x20; \* \`UNDELIVERABLE\` - Message wasn't delivered (check the \`error\`)\
> &#x20; \* \`UNKNOWN\` - Message wasn't delivered due to a unknown reason\
> &#x20; \* \`REJECTED\` - Message was rejected by the supplier (check the \`error\`)\
> \* \`type\`- type of the callback, either \`DLR\` for delivery notification or \`MO\` for mobile originated message\
> \* \`error\` - The error code returned by the supplier (check the table below for possible values)\
> \
> \| EC   | ERROR DESCRIPTION                                                                                  |\
> \| ---- | -------------------------------------------------------------------------------------------------- |\
> \| 0    | DELIVERED                                                                                          |\
> \| 1    | UNKNOWN\_SUBSCRIBER                                                                                 |\
> \| 5    | UNIDENTIFIED\_SUBSCRIBER                                                                            |\
> \| 9    | ILLEGAL\_SUBSCRIBER                                                                                 |\
> \| 11   | TELESERVICE\_NOT\_PROVISIONED                                                                        |\
> \| 13   | CALL\_BARRED                                                                                        |\
> \| 21   | FACILITY\_NOT\_SUPPORTED                                                                             |\
> \| 27   | ABSENT\_SUBSCRIBER                                                                                  |\
> \| 31   | SUBSCRIBER\_BUSY\_FOR\_MT\_SMS                                                                         |\
> \| 32   | DELIVERY\_FAILURE                                                                                   |\
> \| 34   | SYSTEM\_FAILURE                                                                                     |\
> \| 36   | UNEXPECTED\_DATA\_VALUE                                                                              |\
> \| 37   | MEMORY\_CAPACITY\_EXCEEDED                                                                           |\
> \| 38   | PREFIX\_NOT\_RESOLVED                                                                                |\
> \| 39   | IMSI\_BLACKLISTED                                                                                   |\
> \| 40   | DEST\_ADDRESS\_BLACKLISTED                                                                           |\
> \| 41   | TIME\_OUT                                                                                           |\
> \| 43   | INVALID\_ORIGINATOR\_ADDRESS                                                                         |\
> \| 100  | GENERAL\_ERROR                                                                                      |\
> \| 200  | EQUIPMENT\_PROTOCOL\_ERROR                                                                           |\
> \| 201  | UNKNOWN\_MSC                                                                                        |\
> \| 202  | CONGESTION\_ERROR                                                                                   |\
> \| 203  | PARAMETER\_MISSMATCH                                                                                |\
> \| 204  | INITIATING\_RELEASE                                                                                 |\
> \| 205  | POTENTIAL\_VERSION\_INCOMPATIBILITY                                                                  |\
> \| 206  | REMOTE\_NODE\_NOT\_REACHABLE                                                                          |\
> \| 207  | MTP\_FAILURE                                                                                        |\
> \| 346  | CLIENT\_NETWORK\_FORBIDDEN (In a case of MNP being performed)                                        |\
> \| 351  | INVALID\_PREFIX\_OR\_DESTINATION                                                                      |\
> \| 4100 | EXPIRED\_ON\_FORCE\_RETRY (When the time to live has been configured for delivery and it has expired) |\
> \
> \## Callback request example (MO - mobile originated message)\
> \
> \### POST /\<callback\_url>\
> \
> \`\`\`json\
> {\
> &#x20; "from": "16197012345",\
> &#x20; "message\_id": "2d7114a6-bd45-4022-98ab-15d36cc2b9bd",\
> &#x20; "text": "STOP",\
> &#x20; "to": "18888112345",\
> &#x20; "type": "MO"\
> }\
> \`\`\`\
> \
> Each request contains the following information:\
> \
> \* \`message\_id\` - the id of the mobile originated message\
> \* \`from\` - the mobile number the message has been sent from\
> \* \`to\` - the mobile number which has received the message\
> \* \`type\`- type of the callback, either \`DLR\` for delivery notification or \`MO\` for mobile originated message\
> \* \`text\` - the text of the message which has been sent \`from\` to \`to\` number<br>

````json
{"openapi":"3.0.3","info":{"title":"SMS Template API","version":"1.0.0"},"servers":[{"url":"https://messaging-api.bind.hr","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-KEY","description":"API key header."}},"schemas":{"SendRequest":{"type":"object","properties":{"to":{"type":"string","description":"Destination MSISDN in international format (e.g., 44...)"},"callback_url":{"type":"string","format":"uri","nullable":true},"params":{"type":"object","description":"Dynamic template parameters.","additionalProperties":{"type":"string"}}}},"SendResponse":{"type":"object","properties":{"status":{"type":"string","enum":["ACCEPTED","REJECTED"]},"message_id":{"type":"string","description":"Message id (UUID)"},"error_message":{"type":"string"},"cost":{"type":"number","description":"Cost of the message"},"count":{"type":"integer","description":"Number of messages sent"}},"required":["status","error_message","cost","count"]},"SendError":{"type":"object","properties":{"status":{"type":"string","enum":["REJECTED"]},"error_message":{"type":"string"}},"required":["status","error_message"]}}},"paths":{"/v1.0/sms/template/{id}/send":{"post":{"tags":["Send templated message"],"summary":"Send an SMS using a template","description":"Provide the destination number `to`, and optional `callback_url`,\nplus all template parameters under `params` as additional JSON fields (all string values).\nCheck the Templates API for fetching the template `id`.\n\n## Callback request example (DLR - delivery notification)\n\n### POST /<callback_url>\n\n```json\n{\n  \"error\": \"000\",\n  \"from\": \"18888112345\",\n  \"message_id\": \"8bd71f49-6f42-4729-bf5e-ecf857747633\",\n  \"status\": \"DELIVERED\",\n  \"to\": \"16197012345\",\n  \"type\": \"DLR\"\n}\n```\n\nEach request contains the following information:\n\n* `message_id` - the id of the message which has been returned following `/send`  request\n* `from` - the source address the message was sent from\n* `to` - the destination address which has received the message\n* `status`- the status of the message\n  * `DELIVERED` - Message has been delivered\n  * `EXPIRED` - Message wasn't delivered within the 48 hour period\n  * `UNDELIVERABLE` - Message wasn't delivered (check the `error`)\n  * `UNKNOWN` - Message wasn't delivered due to a unknown reason\n  * `REJECTED` - Message was rejected by the supplier (check the `error`)\n* `type`- type of the callback, either `DLR` for delivery notification or `MO` for mobile originated message\n* `error` - The error code returned by the supplier (check the table below for possible values)\n\n| EC   | ERROR DESCRIPTION                                                                                  |\n| ---- | -------------------------------------------------------------------------------------------------- |\n| 0    | DELIVERED                                                                                          |\n| 1    | UNKNOWN_SUBSCRIBER                                                                                 |\n| 5    | UNIDENTIFIED_SUBSCRIBER                                                                            |\n| 9    | ILLEGAL_SUBSCRIBER                                                                                 |\n| 11   | TELESERVICE_NOT_PROVISIONED                                                                        |\n| 13   | CALL_BARRED                                                                                        |\n| 21   | FACILITY_NOT_SUPPORTED                                                                             |\n| 27   | ABSENT_SUBSCRIBER                                                                                  |\n| 31   | SUBSCRIBER_BUSY_FOR_MT_SMS                                                                         |\n| 32   | DELIVERY_FAILURE                                                                                   |\n| 34   | SYSTEM_FAILURE                                                                                     |\n| 36   | UNEXPECTED_DATA_VALUE                                                                              |\n| 37   | MEMORY_CAPACITY_EXCEEDED                                                                           |\n| 38   | PREFIX_NOT_RESOLVED                                                                                |\n| 39   | IMSI_BLACKLISTED                                                                                   |\n| 40   | DEST_ADDRESS_BLACKLISTED                                                                           |\n| 41   | TIME_OUT                                                                                           |\n| 43   | INVALID_ORIGINATOR_ADDRESS                                                                         |\n| 100  | GENERAL_ERROR                                                                                      |\n| 200  | EQUIPMENT_PROTOCOL_ERROR                                                                           |\n| 201  | UNKNOWN_MSC                                                                                        |\n| 202  | CONGESTION_ERROR                                                                                   |\n| 203  | PARAMETER_MISSMATCH                                                                                |\n| 204  | INITIATING_RELEASE                                                                                 |\n| 205  | POTENTIAL_VERSION_INCOMPATIBILITY                                                                  |\n| 206  | REMOTE_NODE_NOT_REACHABLE                                                                          |\n| 207  | MTP_FAILURE                                                                                        |\n| 346  | CLIENT_NETWORK_FORBIDDEN (In a case of MNP being performed)                                        |\n| 351  | INVALID_PREFIX_OR_DESTINATION                                                                      |\n| 4100 | EXPIRED_ON_FORCE_RETRY (When the time to live has been configured for delivery and it has expired) |\n\n## Callback request example (MO - mobile originated message)\n\n### POST /<callback_url>\n\n```json\n{\n  \"from\": \"16197012345\",\n  \"message_id\": \"2d7114a6-bd45-4022-98ab-15d36cc2b9bd\",\n  \"text\": \"STOP\",\n  \"to\": \"18888112345\",\n  \"type\": \"MO\"\n}\n```\n\nEach request contains the following information:\n\n* `message_id` - the id of the mobile originated message\n* `from` - the mobile number the message has been sent from\n* `to` - the mobile number which has received the message\n* `type`- type of the callback, either `DLR` for delivery notification or `MO` for mobile originated message\n* `text` - the text of the message which has been sent `from` to `to` number\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"},"description":"Template id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendRequest"}}}},"responses":{"200":{"description":"Accepted or rejected by business validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendResponse"}}}},"400":{"description":"Request invalid (e.g. missing uuid or template parameter validation failure)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendError"}}}},"401":{"description":"Unauthorized (missing/invalid API key)"},"404":{"description":"Template not found"},"500":{"description":"Failed to send"}}}}}}
````


# Send Basic Message

## Send basic message

> This API is granted only to customers with verified companies after a review compared to the templated API which is granted by default.\
> \
> \## Callback request example (DLR - delivery notification)\
> \
> \### POST /\<callback\_url>\
> \
> \`\`\`json\
> {\
> &#x20; "error": "000",\
> &#x20; "from": "18888112345",\
> &#x20; "message\_id": "8bd71f49-6f42-4729-bf5e-ecf857747633",\
> &#x20; "status": "DELIVERED",\
> &#x20; "to": "16197012345",\
> &#x20; "type": "DLR"\
> }\
> \`\`\`\
> \
> Each request contains the following information:\
> \
> \* \`message\_id\` - the id of the message which has been returned following \`/send\`  request\
> \* \`from\` - the source address the message was sent from\
> \* \`to\` - the destination address which has received the message\
> \* \`status\`- the status of the message\
> &#x20; \* \`DELIVERED\` - Message has been delivered\
> &#x20; \* \`EXPIRED\` - Message wasn't delivered within the 48 hour period\
> &#x20; \* \`UNDELIVERABLE\` - Message wasn't delivered (check the \`error\`)\
> &#x20; \* \`UNKNOWN\` - Message wasn't delivered due to a unknown reason\
> &#x20; \* \`REJECTED\` - Message was rejected by the supplier (check the \`error\`)\
> \* \`type\`- type of the callback, either \`DLR\` for delivery notification or \`MO\` for mobile originated message\
> \* \`error\` - The error code returned by the supplier (check the table below for possible values)\
> \
> \| EC   | ERROR DESCRIPTION                                                                                  |\
> \| ---- | -------------------------------------------------------------------------------------------------- |\
> \| 0    | DELIVERED                                                                                          |\
> \| 1    | UNKNOWN\_SUBSCRIBER                                                                                 |\
> \| 5    | UNIDENTIFIED\_SUBSCRIBER                                                                            |\
> \| 9    | ILLEGAL\_SUBSCRIBER                                                                                 |\
> \| 11   | TELESERVICE\_NOT\_PROVISIONED                                                                        |\
> \| 13   | CALL\_BARRED                                                                                        |\
> \| 21   | FACILITY\_NOT\_SUPPORTED                                                                             |\
> \| 27   | ABSENT\_SUBSCRIBER                                                                                  |\
> \| 31   | SUBSCRIBER\_BUSY\_FOR\_MT\_SMS                                                                         |\
> \| 32   | DELIVERY\_FAILURE                                                                                   |\
> \| 34   | SYSTEM\_FAILURE                                                                                     |\
> \| 36   | UNEXPECTED\_DATA\_VALUE                                                                              |\
> \| 37   | MEMORY\_CAPACITY\_EXCEEDED                                                                           |\
> \| 38   | PREFIX\_NOT\_RESOLVED                                                                                |\
> \| 39   | IMSI\_BLACKLISTED                                                                                   |\
> \| 40   | DEST\_ADDRESS\_BLACKLISTED                                                                           |\
> \| 41   | TIME\_OUT                                                                                           |\
> \| 43   | INVALID\_ORIGINATOR\_ADDRESS                                                                         |\
> \| 100  | GENERAL\_ERROR                                                                                      |\
> \| 200  | EQUIPMENT\_PROTOCOL\_ERROR                                                                           |\
> \| 201  | UNKNOWN\_MSC                                                                                        |\
> \| 202  | CONGESTION\_ERROR                                                                                   |\
> \| 203  | PARAMETER\_MISSMATCH                                                                                |\
> \| 204  | INITIATING\_RELEASE                                                                                 |\
> \| 205  | POTENTIAL\_VERSION\_INCOMPATIBILITY                                                                  |\
> \| 206  | REMOTE\_NODE\_NOT\_REACHABLE                                                                          |\
> \| 207  | MTP\_FAILURE                                                                                        |\
> \| 346  | CLIENT\_NETWORK\_FORBIDDEN (In a case of MNP being performed)                                        |\
> \| 351  | INVALID\_PREFIX\_OR\_DESTINATION                                                                      |\
> \| 4100 | EXPIRED\_ON\_FORCE\_RETRY (When the time to live has been configured for delivery and it has expired) |\
> \
> \## Callback request example (MO - mobile originated message)\
> \
> \### POST /\<callback\_url>\
> \
> \`\`\`json\
> {\
> &#x20; "from": "16197012345",\
> &#x20; "message\_id": "2d7114a6-bd45-4022-98ab-15d36cc2b9bd",\
> &#x20; "text": "STOP",\
> &#x20; "to": "18888112345",\
> &#x20; "type": "MO"\
> }\
> \`\`\`\
> \
> Each request contains the following information:\
> \
> \* \`message\_id\` - the id of the mobile originated message\
> \* \`from\` - the mobile number the message has been sent from\
> \* \`to\` - the mobile number which has received the message\
> \* \`type\`- type of the callback, either \`DLR\` for delivery notification or \`MO\` for mobile originated message\
> \* \`text\` - the text of the message which has been sent \`from\` to \`to\` number<br>

````json
{"openapi":"3.0.3","info":{"title":"SMS Template API","version":"1.0.0"},"servers":[{"url":"https://messaging-api.bind.hr","description":"Production"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-KEY","description":"API key header."}}},"paths":{"/v1.0/send":{"post":{"tags":["Send basic message"],"summary":"Send basic message","description":"This API is granted only to customers with verified companies after a review compared to the templated API which is granted by default.\n\n## Callback request example (DLR - delivery notification)\n\n### POST /<callback_url>\n\n```json\n{\n  \"error\": \"000\",\n  \"from\": \"18888112345\",\n  \"message_id\": \"8bd71f49-6f42-4729-bf5e-ecf857747633\",\n  \"status\": \"DELIVERED\",\n  \"to\": \"16197012345\",\n  \"type\": \"DLR\"\n}\n```\n\nEach request contains the following information:\n\n* `message_id` - the id of the message which has been returned following `/send`  request\n* `from` - the source address the message was sent from\n* `to` - the destination address which has received the message\n* `status`- the status of the message\n  * `DELIVERED` - Message has been delivered\n  * `EXPIRED` - Message wasn't delivered within the 48 hour period\n  * `UNDELIVERABLE` - Message wasn't delivered (check the `error`)\n  * `UNKNOWN` - Message wasn't delivered due to a unknown reason\n  * `REJECTED` - Message was rejected by the supplier (check the `error`)\n* `type`- type of the callback, either `DLR` for delivery notification or `MO` for mobile originated message\n* `error` - The error code returned by the supplier (check the table below for possible values)\n\n| EC   | ERROR DESCRIPTION                                                                                  |\n| ---- | -------------------------------------------------------------------------------------------------- |\n| 0    | DELIVERED                                                                                          |\n| 1    | UNKNOWN_SUBSCRIBER                                                                                 |\n| 5    | UNIDENTIFIED_SUBSCRIBER                                                                            |\n| 9    | ILLEGAL_SUBSCRIBER                                                                                 |\n| 11   | TELESERVICE_NOT_PROVISIONED                                                                        |\n| 13   | CALL_BARRED                                                                                        |\n| 21   | FACILITY_NOT_SUPPORTED                                                                             |\n| 27   | ABSENT_SUBSCRIBER                                                                                  |\n| 31   | SUBSCRIBER_BUSY_FOR_MT_SMS                                                                         |\n| 32   | DELIVERY_FAILURE                                                                                   |\n| 34   | SYSTEM_FAILURE                                                                                     |\n| 36   | UNEXPECTED_DATA_VALUE                                                                              |\n| 37   | MEMORY_CAPACITY_EXCEEDED                                                                           |\n| 38   | PREFIX_NOT_RESOLVED                                                                                |\n| 39   | IMSI_BLACKLISTED                                                                                   |\n| 40   | DEST_ADDRESS_BLACKLISTED                                                                           |\n| 41   | TIME_OUT                                                                                           |\n| 43   | INVALID_ORIGINATOR_ADDRESS                                                                         |\n| 100  | GENERAL_ERROR                                                                                      |\n| 200  | EQUIPMENT_PROTOCOL_ERROR                                                                           |\n| 201  | UNKNOWN_MSC                                                                                        |\n| 202  | CONGESTION_ERROR                                                                                   |\n| 203  | PARAMETER_MISSMATCH                                                                                |\n| 204  | INITIATING_RELEASE                                                                                 |\n| 205  | POTENTIAL_VERSION_INCOMPATIBILITY                                                                  |\n| 206  | REMOTE_NODE_NOT_REACHABLE                                                                          |\n| 207  | MTP_FAILURE                                                                                        |\n| 346  | CLIENT_NETWORK_FORBIDDEN (In a case of MNP being performed)                                        |\n| 351  | INVALID_PREFIX_OR_DESTINATION                                                                      |\n| 4100 | EXPIRED_ON_FORCE_RETRY (When the time to live has been configured for delivery and it has expired) |\n\n## Callback request example (MO - mobile originated message)\n\n### POST /<callback_url>\n\n```json\n{\n  \"from\": \"16197012345\",\n  \"message_id\": \"2d7114a6-bd45-4022-98ab-15d36cc2b9bd\",\n  \"text\": \"STOP\",\n  \"to\": \"18888112345\",\n  \"type\": \"MO\"\n}\n```\n\nEach request contains the following information:\n\n* `message_id` - the id of the mobile originated message\n* `from` - the mobile number the message has been sent from\n* `to` - the mobile number which has received the message\n* `type`- type of the callback, either `DLR` for delivery notification or `MO` for mobile originated message\n* `text` - the text of the message which has been sent `from` to `to` number\n","operationId":"send","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["from","to","text"],"properties":{"from":{"type":"string","description":"Defines which sender name is going to be visible to the customer once the message has been received on the mobile handset","default":"YourCompany"},"to":{"type":"string","description":"Defines a number to which the message is being set","default":"447916123456"},"text":{"type":"string","description":"The message text which is being sent to the mobile handset","default":"Your one time pin code is 123456"},"callback_url":{"type":"string","description":"Optional URL to which updates related to message delivery will be received","default":""}}}}}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"oneOf":[{"title":"Accepted","type":"object","properties":{"status":{"type":"string"},"message_id":{"type":"string"},"error_message":{"type":"string"},"cost":{"type":"number"},"count":{"type":"integer"}}},{"title":"Rejected","type":"object","properties":{"status":{"type":"string"},"message_id":{"type":"string"},"error_message":{"type":"string"}}}]}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"property":{"type":"string"},"error":{"type":"string"}}}}}}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"error_message":{"type":"string"}}}}}},"429":{"description":"429","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}},"500":{"description":"500","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}}},"deprecated":false}}}}
````


# Use case

The **2FA Messaging API** lets you send time-sensitive authentication codes (2FA) to your users and verify the codes they enter. This ensures that only legitimate users can access your services.

**Key Roles**

* **UserService** – Your service or application that uses the API to authenticate users.
* **API** – The Bind 2FA Messaging API.
* **Recipient** – The end user of your mobile application who owns a valid phone number.

***

### Flow diagram

{% tabs %}
{% tab title="Simplified flow" %}

<figure><img src="https://1710642247-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSTYqSPgYZ3EediTRZzwK%2Fuploads%2F7hHQG3M18mij4F0vJSFE%2Fimage.png?alt=media&amp;token=bc22117a-984a-43f1-8c52-a2e3e213d11c" alt="" width="375"><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Flow diagram" %}

<figure><img src="https://1710642247-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FSTYqSPgYZ3EediTRZzwK%2Fuploads%2F6C6HX6RlHRcpbEyfo9bR%2Fimage.png?alt=media&amp;token=ef4c3f7b-2cc1-4d0b-8e24-24ffb72846e6" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

### How the 2FA Flow Works

**Step-by-Step Process**

1. **Recipient starts verification**\
   The Recipient opens your mobile application (**UserService**) and starts the 2FA verification process.
2. **UserService requests a 2FA code**\
   The **UserService** sends a request to the **API** using\
   `POST /api/v1.0/2fa/request`.
   * The **API** responds with a `request_id` that uniquely identifies this attempt.
   * Example response:

     ```json
     {
       "status": "ACCEPTED",
       "request_id": "uuid",
       "error_message": "OK"
     }
     ```
3. **API delivers the 2FA code**\
   The **API** generates and sends the 2FA code to the **Recipient** via SMS or another messaging channel.
4. **Recipient enters the code**\
   The **Recipient** types the received 2FA code into the **UserService** mobile interface.
5. **UserService validates the code**\
   The **UserService** calls\
   `POST /api/v1.0/2fa/validate`\
   with the entered code and the `request_id`.
   * Example request:

     ```json
     {
       "code": "123456",
       "request_id": "uuid"
     }
     ```
   * If the code is correct, the **API** responds:

     ```json
     {
       "verified": true,
       "status": "success"
     }
     ```
6. **Verification complete**\
   The **UserService** confirms that the **Recipient** has been successfully authenticated.

***

### What’s Next

You now understand how to authenticate users using the Bind 2FA Messaging API.\
Continue to the next section of the documentation to explore the API endpoints that support this flow.


# Request

## request

> Initiate the delivery of a 2FA code to a recipient.

```json
{"openapi":"3.1.0","info":{"title":"messaging-2fa-api","version":"1.0"},"servers":[{"url":"https://messaging-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}}},"paths":{"/v1.0/2fa/request":{"post":{"summary":"request","description":"Initiate the delivery of a 2FA code to a recipient.","operationId":"2fa-api-request-endpoint","tags":["Request"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["to","template_id"],"properties":{"to":{"type":"string","description":"The destination number for the 2FA message.","default":"447916123456"},"template_id":{"type":"string","description":"The id of the template which is being sent to the recipient","default":"11bf5b37-e0b8-42e0-8dcf-dc8c4aefc123"},"parameters":{"type":"object","description":"A list of key-value parameters to be applied to the template. Note that `${code}` is a reserved parameter and will be ignored if provided.","required":["key"],"properties":{"key":{"type":"string","default":"value"}}}}}}}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"status":{"type":"string"},"request_id":{"type":"string"},"error_message":{"type":"string"}}},{"title":"Rejected","type":"object","properties":{"status":{"type":"string"},"request_id":{"type":"string"},"error_message":{"type":"string"}}}]}}}},"400":{"description":"400","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"array","items":{"type":"object","properties":{"property":{"type":"string"},"error":{"type":"string"}}}}}}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"error_message":{"type":"string"}}}}}},"429":{"description":"429","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}},"500":{"description":"500","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}}},"deprecated":false}}}}
```


# Validate

## validate

> Verify a submitted 2FA code against a previous request.

```json
{"openapi":"3.1.0","info":{"title":"messaging-2fa-api","version":"1.0"},"servers":[{"url":"https://messaging-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}}},"paths":{"/v1.0/2fa/validate":{"post":{"summary":"validate","description":"Verify a submitted 2FA code against a previous request.","operationId":"2fa-api-validate-endpoint","tags":["Validate"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","request_id"],"properties":{"code":{"type":"string","description":"The 2FA code entered by the recipient.","default":"123456"},"request_id":{"type":"string","description":"The request_id received as a part of /request response","default":"9135605a-7e48-4be8-860c-ecf5840d2770"}}}}}},"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"oneOf":[{"title":"Verified","type":"object","properties":{"verified":{"type":"boolean","default":true},"status":{"type":"string"}}},{"title":"Not verified","type":"object","properties":{"verified":{"type":"boolean","default":true},"status":{"type":"string"}}}]}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"error_message":{"type":"string"}}}}}},"429":{"description":"429","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}},"500":{"description":"500","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}}},"deprecated":false}}}}
```


# Templates

## template/get

> Retrieve available message templates for 2FA delivery.

```json
{"openapi":"3.1.0","info":{"title":"messaging-2fa-api","version":"1.0"},"servers":[{"url":"https://messaging-api.bind.hr"}],"security":[{"default":[]}],"components":{"securitySchemes":{"default":{"type":"apiKey","in":"header","name":"X-API-KEY"}}},"paths":{"/v1.0/2fa/template":{"get":{"summary":"template/get","description":"Retrieve available message templates for 2FA delivery.","operationId":"2fa-api-template-get-endpoint","tags":["Templates"],"responses":{"200":{"description":"200","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"from":{"type":"string"},"text":{"type":"string"},"ttl":{"type":"integer","default":0}}}}}}}}},"401":{"description":"401","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"error_message":{"type":"string"}}}}}},"429":{"description":"429","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}},"500":{"description":"500","content":{"application/json":{"schema":{"type":"object","properties":{"error_message":{"type":"string"}}}}}}},"deprecated":false}}}}
```


# Channels API


# Send a message

The `channels` list holds the channels to send on, in order. Each entry is self-contained: the channel, the sender profile it goes out from, the recipient and the content.

One entry sends on one channel and that is the whole request. Several entries are tried in order - the message goes out on the first, and moves to the next only if that one does not deliver within its `failover_after`. There is no failover flag; the number of entries is what decides it.

The request is all-or-nothing: if any entry is invalid or cannot be sent, the whole request is rejected and nothing goes out.

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"servers":[{"url":"https://{host}","description":"Base URL for the API. Everything below is relative to it. `host` defaults to the production endpoint; we tell you if your account uses a different one.\n","variables":{"host":{"default":"channels.bind.hr"}}}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","description":"Your API key as `Authorization: Bearer <key>`. The `Bearer` prefix is case-sensitive.\n\nYour key can additionally be restricted to the addresses you send from. Give us the list as individual addresses or CIDR blocks - `203.0.113.4`, `198.51.100.0/24`, `2001:db8::/32` - and a request from anywhere else is rejected with `IP_NOT_ALLOWED`. IPv4 and IPv6 are listed separately: an IPv4 range does not cover you if you reach us over IPv6, so if you use both, send us both. Leave the restriction empty and we accept your key from any address.\n"}},"schemas":{"MessageRequest":{"type":"object","required":["channels"],"properties":{"channels":{"type":"array","minItems":1,"description":"The channels to send on, in order. At least one. Each entry carries everything that channel needs.\n","items":{"$ref":"#/components/schemas/ChannelEntry"}}}},"ChannelEntry":{"type":"object","required":["channel","profile_id","to","content"],"description":"One channel to send on. Everything the send needs is on the entry itself - a missing field is a `400` naming it.\n","properties":{"channel":{"type":"string","description":"Channel name, e.g. `viber` or `sms`."},"profile_id":{"type":"string","format":"uuid","description":"The sender profile this channel sends from, by the UUID we issued for it. We fill in the sender from it, and it is what the message is attributed to in your reporting. A profile belongs to one channel, so each entry has its own. A UUID that matches no active profile of yours is rejected with `PROFILE_NOT_FOUND`.\n"},"to":{"type":"string","description":"Recipient phone number in international format."},"content":{"$ref":"#/components/schemas/Content"},"failover_after":{"type":"integer","minimum":1,"description":"How many seconds to wait for delivery on this channel before moving to the next entry. Only meaningful when there is a next entry.\n"}}},"Content":{"description":"For `sms`, the content is a plain text string. For rich channels like `viber` it is an object. The two are interchangeable for plain text: a string sent to Viber goes out as a text message, and `{\"type\": \"text\", \"text\": \"...\"}` sent to SMS goes out as that text.\n","oneOf":[{"type":"string","description":"Plain text."},{"$ref":"#/components/schemas/ViberContent"}]},"ViberContent":{"type":"object","description":"Viber message content. Not every combination of fields is a valid Viber message, so the ones that work are listed here in full. Anything else is rejected with `UNSUPPORTED_CONTENT`. There is a ready-made example of each under **Request samples** on both send endpoints.\n\n**These work:**\n\n| Content | With text | With a button | |---|---|---| | `text` | - | yes | | `media_url` (image) | yes | yes | | `video` | yes | yes | | `file` | no | no | | `carousel` | yes | no | | `list` | yes | no |\n\n**These do not:** an image and a video (or a file) together; a carousel and a list together; a file with anything else at all; a button on its own, with no text, image or video to attach it to; a button with no `caption`; a completely empty content object. `ttl` may accompany any of the working combinations.\n\nOnly fields you actually fill in are sent on; empty strings, empty objects and empty lists count as not set. Keys are snake_case, and the camelCase spelling noted per field also works.\n","properties":{"text":{"type":"string"},"media_url":{"type":"string","format":"uri","description":"Image URL. Also accepted as `mediaUrl`."},"video":{"type":"object","description":"A video. This is an object, not a plain URL string.","properties":{"media_url":{"type":"string","format":"uri","description":"Video URL. Also accepted as `mediaUrl`."},"thumbnail":{"type":"string","format":"uri"}}},"file":{"type":"object","description":"A file. This is an object, not a plain URL string. A file must be sent on its own - no text, button, image or video alongside it.\n","properties":{"media_url":{"type":"string","format":"uri","description":"File URL. Also accepted as `mediaUrl`."},"file_name":{"type":"string","description":"Also accepted as `fileName`."}}},"button":{"type":"object","required":["caption"],"description":"A button needs text, an image or a video alongside it, and it must have a caption.\n","properties":{"caption":{"type":"string","description":"The button label. Required."},"action":{"type":"string","description":"What the button opens - an `https://` or `viber://` link. Note the key is `action`; a `url` key is not supported and is ignored.\n"}}},"carousel":{"type":"object","description":"A carousel of cards. Send it on its own or with text - not with an image, video, file, button or list.\n","properties":{"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"image_url":{"type":"string","format":"uri","description":"Also accepted as `imageUrl`."},"primary_button":{"$ref":"#/components/schemas/CarouselButton"},"secondary_button":{"$ref":"#/components/schemas/CarouselButton"}}}}}},"list":{"type":"object","description":"A survey list. Send it on its own or with text - not with an image, video, file, button or carousel. `survey.options` must have at least one option.\n","properties":{"survey":{"type":"object","properties":{"options":{"type":"array","minItems":1,"items":{"type":"string"}}}}}},"ttl":{"type":"integer","description":"How long the message stays valid, in seconds."},"type":{"type":"string","description":"Accepted and ignored on Viber. It only matters if you send the same object to the SMS channel, where `\"text\"` marks it as convertible to plain text.\n"},"message_type":{"type":"string","description":"Accepted and ignored. Also accepted as `messageType`."}}},"CarouselButton":{"type":"object","description":"A button on a carousel card. The containing keys are also accepted as `primaryButton` / `secondaryButton`.\n","properties":{"label":{"type":"string"},"action_url":{"type":"string","format":"uri","description":"Also accepted as `actionUrl`."}}},"Problem":{"type":"object","description":"Every error, in one shape - `application/problem+json` (RFC 9457). There is not a different body per kind of failure, so you only need one parser.\n","required":["title","status","code"],"properties":{"title":{"type":"string","description":"Short human-readable summary of what went wrong. Meant for your logs, not for branching on - the wording may change.\n"},"status":{"type":"integer","description":"The HTTP status, repeated here so the body stands on its own."},"code":{"type":"string","description":"Stable machine-readable code. **This is the one to branch on** - it never changes for a given condition, while the status and title may be refined.\n","enum":["VALIDATION_FAILED","UNAUTHORIZED","OUT_OF_BALANCE","CLIENT_PRICE_NOT_FOUND","IP_NOT_ALLOWED","DISABLED_CONNECTION","DISABLED_CLIENT","CLIENT_ARCHIVED","DISABLED_ACCOUNT","DISABLED_PRODUCT","DISABLED_CLIENT_PRODUCT","CHANNEL_DISABLED","INVALID_SENDER","DESTINATION_COUNTRY_FORBIDDEN","UNKNOWN_CHANNEL","CHANNEL_NOT_CONFIGURED","CLIENT_PRODUCT_DOES_NOT_EXIST","PROFILE_NOT_FOUND","UNKNOWN_BRAND","NO_DNS_CONFIGURED","NOT_FOUND","METHOD_NOT_ALLOWED","UNSUPPORTED_MEDIA_TYPE","PAYLOAD_TOO_LARGE","UNSUPPORTED_CONTENT","REJECTED","TOO_MANY_REQUESTS","NO_ROUTES","INTERNAL_ERROR"]},"errors":{"type":"array","description":"Only on a `400`: one entry per offending field, so you can point at the exact problem rather than re-reading the whole request.\n","items":{"$ref":"#/components/schemas/ErrorEntry"}}}},"ErrorEntry":{"type":"object","properties":{"property":{"type":"string","description":"The request field that is wrong."},"error":{"type":"string","description":"What is wrong with it."}}},"DeliveryReport":{"type":"object","description":"The delivery report we POST to your account's default webhook.","properties":{"type":{"type":"string","enum":["DLR"]},"message_id":{"type":"string","format":"uuid","description":"The `request_id` you got when the message was accepted."},"to":{"type":"string","description":"Recipient phone number."},"status":{"type":"string","enum":["DELIVERED","SEEN","UNDELIVERABLE"],"description":"`DELIVERED` and `UNDELIVERABLE` are final - the message is done, and every channel it could be tried on has been. `SEEN` is a read receipt and is not final; expect it in addition to, not instead of, a final report.\n"},"error":{"type":"string","description":"Result code - `000` for `DELIVERED` and `SEEN`, `001` for a generic failure, or a more specific code when the channel gives us one.\n"},"cost":{"type":"number","nullable":true,"description":"What this attempt actually charged, in your account currency - `0` if the message was never charged (e.g. an `UNDELIVERABLE` outcome on an account billed per delivery). May differ from the `cost` on the send response, which was only an indicative estimate for the first channel tried.\n"}}}},"responses":{"Accepted":{"description":"Accepted for delivery. This is a `202`, not a `200`, on purpose: we have queued the message, not delivered it. The outcome arrives later in the delivery report.\n","content":{"application/json":{"schema":{"type":"object","properties":{"request_id":{"type":"string","format":"uuid","description":"Id for this message. One id covers every channel it is tried on, and it comes back as `message_id` in the delivery report. Store it - it is what we need for any support question about the message.\n"},"cost":{"type":"number","nullable":true,"description":"Indicative price for the first channel tried, in your account currency. `null` when no price could be resolved. This is only an estimate: a failover may deliver on a different, differently-priced channel, and the delivery report's `cost` is what was actually charged - the two may differ.\n"}}}}}},"ValidationFailed":{"description":"Something in the request is wrong. `errors` names each offending field. Fix the request before retrying - repeating it unchanged will fail the same way.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Unauthorized":{"description":"Your API key was not accepted. This status means only that - every other kind of rejection has its own status, so a `401` is always worth checking your key over.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"PaymentRequired":{"description":"Not enough balance to send. Top up and retry.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Forbidden":{"description":"Your key is fine, but this send is not allowed. Retrying will not help - the `code` says what to fix, and most of these need us to change something on your account.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"NotFound":{"description":"Something named in the request does not exist - the channel, the sender profile, or the URL itself.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"MethodNotAllowed":{"description":"Right URL, wrong method. This endpoint is POST only.","headers":{"Allow":{"description":"The methods this endpoint accepts.","schema":{"type":"string"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"PayloadTooLarge":{"description":"The request body is larger than we accept. A send is a small JSON document - content plus a short list of failover channels, with media sent by URL rather than inline - so this normally means something unintended was posted.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"UnsupportedMediaType":{"description":"The body must be JSON, sent with `Content-Type: application/json`. A form or plain-text body is not accepted.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"Unprocessable":{"description":"The request was understood but cannot be sent as it stands. Retrying it unchanged will not help.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"TooManyRequests":{"description":"You are sending faster than the rate agreed for your API key. The limit is a per-second one, so it clears almost immediately - wait out the `Retry-After` and send again. Nothing was sent, so the request is safe to repeat as-is.\n","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Always `1`, because the limit is counted in one-second windows - your allowance is back at the next whole second.\n","schema":{"type":"integer"}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"InternalError":{"description":"Something went wrong on our side. Safe to retry.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"ServiceUnavailable":{"description":"No delivery route to that number at the moment. This one is temporary and on our side, so the same request may well succeed later.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"paths":{"/v1/messages":{"post":{"operationId":"createMessage","summary":"Send a message","description":"The `channels` list holds the channels to send on, in order. Each entry is self-contained: the channel, the sender profile it goes out from, the recipient and the content.\n\nOne entry sends on one channel and that is the whole request. Several entries are tried in order - the message goes out on the first, and moves to the next only if that one does not deliver within its `failover_after`. There is no failover flag; the number of entries is what decides it.\n\nThe request is all-or-nothing: if any entry is invalid or cannot be sent, the whole request is rejected and nothing goes out.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageRequest"}}}},"responses":{"202":{"$ref":"#/components/responses/Accepted"},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"405":{"$ref":"#/components/responses/MethodNotAllowed"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"callbacks":{"deliveryReport":{"https://{your-configured-webhook}":{"post":{"operationId":"deliveryReport","summary":"Delivery report for a message you sent","description":"Sent once per message, as soon as the outcome is known, to your account's default webhook. If no webhook is configured for your account you get no delivery report.\n\nIf a webhook secret is configured for your account, every call carries it in the `X-Webhook-Secret` header, so you can reject anything that does not present it. Compare the whole value; we send it unchanged on every call. Ask us if you need it in a differently named header.\n\nReply with any `2xx` to acknowledge. Anything else - or a connection failure - is retried with a growing delay for up to two days, after which we stop trying. That window also covers a secret change: while you deploy a new one, rejected reports are retried rather than lost.\n\nReports are paced at the rate agreed for your account, so expect them spread out rather than all at once during a large campaign.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryReport"}}}},"responses":{"2XX":{"description":"Report acknowledged - we will not retry it."}}}}}}}}}}
```


# Models

## The MessageRequest object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"MessageRequest":{"type":"object","required":["channels"],"properties":{"channels":{"type":"array","minItems":1,"description":"The channels to send on, in order. At least one. Each entry carries everything that channel needs.\n","items":{"$ref":"#/components/schemas/ChannelEntry"}}}},"ChannelEntry":{"type":"object","required":["channel","profile_id","to","content"],"description":"One channel to send on. Everything the send needs is on the entry itself - a missing field is a `400` naming it.\n","properties":{"channel":{"type":"string","description":"Channel name, e.g. `viber` or `sms`."},"profile_id":{"type":"string","format":"uuid","description":"The sender profile this channel sends from, by the UUID we issued for it. We fill in the sender from it, and it is what the message is attributed to in your reporting. A profile belongs to one channel, so each entry has its own. A UUID that matches no active profile of yours is rejected with `PROFILE_NOT_FOUND`.\n"},"to":{"type":"string","description":"Recipient phone number in international format."},"content":{"$ref":"#/components/schemas/Content"},"failover_after":{"type":"integer","minimum":1,"description":"How many seconds to wait for delivery on this channel before moving to the next entry. Only meaningful when there is a next entry.\n"}}},"Content":{"description":"For `sms`, the content is a plain text string. For rich channels like `viber` it is an object. The two are interchangeable for plain text: a string sent to Viber goes out as a text message, and `{\"type\": \"text\", \"text\": \"...\"}` sent to SMS goes out as that text.\n","oneOf":[{"type":"string","description":"Plain text."},{"$ref":"#/components/schemas/ViberContent"}]},"ViberContent":{"type":"object","description":"Viber message content. Not every combination of fields is a valid Viber message, so the ones that work are listed here in full. Anything else is rejected with `UNSUPPORTED_CONTENT`. There is a ready-made example of each under **Request samples** on both send endpoints.\n\n**These work:**\n\n| Content | With text | With a button | |---|---|---| | `text` | - | yes | | `media_url` (image) | yes | yes | | `video` | yes | yes | | `file` | no | no | | `carousel` | yes | no | | `list` | yes | no |\n\n**These do not:** an image and a video (or a file) together; a carousel and a list together; a file with anything else at all; a button on its own, with no text, image or video to attach it to; a button with no `caption`; a completely empty content object. `ttl` may accompany any of the working combinations.\n\nOnly fields you actually fill in are sent on; empty strings, empty objects and empty lists count as not set. Keys are snake_case, and the camelCase spelling noted per field also works.\n","properties":{"text":{"type":"string"},"media_url":{"type":"string","format":"uri","description":"Image URL. Also accepted as `mediaUrl`."},"video":{"type":"object","description":"A video. This is an object, not a plain URL string.","properties":{"media_url":{"type":"string","format":"uri","description":"Video URL. Also accepted as `mediaUrl`."},"thumbnail":{"type":"string","format":"uri"}}},"file":{"type":"object","description":"A file. This is an object, not a plain URL string. A file must be sent on its own - no text, button, image or video alongside it.\n","properties":{"media_url":{"type":"string","format":"uri","description":"File URL. Also accepted as `mediaUrl`."},"file_name":{"type":"string","description":"Also accepted as `fileName`."}}},"button":{"type":"object","required":["caption"],"description":"A button needs text, an image or a video alongside it, and it must have a caption.\n","properties":{"caption":{"type":"string","description":"The button label. Required."},"action":{"type":"string","description":"What the button opens - an `https://` or `viber://` link. Note the key is `action`; a `url` key is not supported and is ignored.\n"}}},"carousel":{"type":"object","description":"A carousel of cards. Send it on its own or with text - not with an image, video, file, button or list.\n","properties":{"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"image_url":{"type":"string","format":"uri","description":"Also accepted as `imageUrl`."},"primary_button":{"$ref":"#/components/schemas/CarouselButton"},"secondary_button":{"$ref":"#/components/schemas/CarouselButton"}}}}}},"list":{"type":"object","description":"A survey list. Send it on its own or with text - not with an image, video, file, button or carousel. `survey.options` must have at least one option.\n","properties":{"survey":{"type":"object","properties":{"options":{"type":"array","minItems":1,"items":{"type":"string"}}}}}},"ttl":{"type":"integer","description":"How long the message stays valid, in seconds."},"type":{"type":"string","description":"Accepted and ignored on Viber. It only matters if you send the same object to the SMS channel, where `\"text\"` marks it as convertible to plain text.\n"},"message_type":{"type":"string","description":"Accepted and ignored. Also accepted as `messageType`."}}},"CarouselButton":{"type":"object","description":"A button on a carousel card. The containing keys are also accepted as `primaryButton` / `secondaryButton`.\n","properties":{"label":{"type":"string"},"action_url":{"type":"string","format":"uri","description":"Also accepted as `actionUrl`."}}}}}}
```

## The ChannelEntry object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"ChannelEntry":{"type":"object","required":["channel","profile_id","to","content"],"description":"One channel to send on. Everything the send needs is on the entry itself - a missing field is a `400` naming it.\n","properties":{"channel":{"type":"string","description":"Channel name, e.g. `viber` or `sms`."},"profile_id":{"type":"string","format":"uuid","description":"The sender profile this channel sends from, by the UUID we issued for it. We fill in the sender from it, and it is what the message is attributed to in your reporting. A profile belongs to one channel, so each entry has its own. A UUID that matches no active profile of yours is rejected with `PROFILE_NOT_FOUND`.\n"},"to":{"type":"string","description":"Recipient phone number in international format."},"content":{"$ref":"#/components/schemas/Content"},"failover_after":{"type":"integer","minimum":1,"description":"How many seconds to wait for delivery on this channel before moving to the next entry. Only meaningful when there is a next entry.\n"}}},"Content":{"description":"For `sms`, the content is a plain text string. For rich channels like `viber` it is an object. The two are interchangeable for plain text: a string sent to Viber goes out as a text message, and `{\"type\": \"text\", \"text\": \"...\"}` sent to SMS goes out as that text.\n","oneOf":[{"type":"string","description":"Plain text."},{"$ref":"#/components/schemas/ViberContent"}]},"ViberContent":{"type":"object","description":"Viber message content. Not every combination of fields is a valid Viber message, so the ones that work are listed here in full. Anything else is rejected with `UNSUPPORTED_CONTENT`. There is a ready-made example of each under **Request samples** on both send endpoints.\n\n**These work:**\n\n| Content | With text | With a button | |---|---|---| | `text` | - | yes | | `media_url` (image) | yes | yes | | `video` | yes | yes | | `file` | no | no | | `carousel` | yes | no | | `list` | yes | no |\n\n**These do not:** an image and a video (or a file) together; a carousel and a list together; a file with anything else at all; a button on its own, with no text, image or video to attach it to; a button with no `caption`; a completely empty content object. `ttl` may accompany any of the working combinations.\n\nOnly fields you actually fill in are sent on; empty strings, empty objects and empty lists count as not set. Keys are snake_case, and the camelCase spelling noted per field also works.\n","properties":{"text":{"type":"string"},"media_url":{"type":"string","format":"uri","description":"Image URL. Also accepted as `mediaUrl`."},"video":{"type":"object","description":"A video. This is an object, not a plain URL string.","properties":{"media_url":{"type":"string","format":"uri","description":"Video URL. Also accepted as `mediaUrl`."},"thumbnail":{"type":"string","format":"uri"}}},"file":{"type":"object","description":"A file. This is an object, not a plain URL string. A file must be sent on its own - no text, button, image or video alongside it.\n","properties":{"media_url":{"type":"string","format":"uri","description":"File URL. Also accepted as `mediaUrl`."},"file_name":{"type":"string","description":"Also accepted as `fileName`."}}},"button":{"type":"object","required":["caption"],"description":"A button needs text, an image or a video alongside it, and it must have a caption.\n","properties":{"caption":{"type":"string","description":"The button label. Required."},"action":{"type":"string","description":"What the button opens - an `https://` or `viber://` link. Note the key is `action`; a `url` key is not supported and is ignored.\n"}}},"carousel":{"type":"object","description":"A carousel of cards. Send it on its own or with text - not with an image, video, file, button or list.\n","properties":{"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"image_url":{"type":"string","format":"uri","description":"Also accepted as `imageUrl`."},"primary_button":{"$ref":"#/components/schemas/CarouselButton"},"secondary_button":{"$ref":"#/components/schemas/CarouselButton"}}}}}},"list":{"type":"object","description":"A survey list. Send it on its own or with text - not with an image, video, file, button or carousel. `survey.options` must have at least one option.\n","properties":{"survey":{"type":"object","properties":{"options":{"type":"array","minItems":1,"items":{"type":"string"}}}}}},"ttl":{"type":"integer","description":"How long the message stays valid, in seconds."},"type":{"type":"string","description":"Accepted and ignored on Viber. It only matters if you send the same object to the SMS channel, where `\"text\"` marks it as convertible to plain text.\n"},"message_type":{"type":"string","description":"Accepted and ignored. Also accepted as `messageType`."}}},"CarouselButton":{"type":"object","description":"A button on a carousel card. The containing keys are also accepted as `primaryButton` / `secondaryButton`.\n","properties":{"label":{"type":"string"},"action_url":{"type":"string","format":"uri","description":"Also accepted as `actionUrl`."}}}}}}
```

## The Content object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"Content":{"description":"For `sms`, the content is a plain text string. For rich channels like `viber` it is an object. The two are interchangeable for plain text: a string sent to Viber goes out as a text message, and `{\"type\": \"text\", \"text\": \"...\"}` sent to SMS goes out as that text.\n","oneOf":[{"type":"string","description":"Plain text."},{"$ref":"#/components/schemas/ViberContent"}]},"ViberContent":{"type":"object","description":"Viber message content. Not every combination of fields is a valid Viber message, so the ones that work are listed here in full. Anything else is rejected with `UNSUPPORTED_CONTENT`. There is a ready-made example of each under **Request samples** on both send endpoints.\n\n**These work:**\n\n| Content | With text | With a button | |---|---|---| | `text` | - | yes | | `media_url` (image) | yes | yes | | `video` | yes | yes | | `file` | no | no | | `carousel` | yes | no | | `list` | yes | no |\n\n**These do not:** an image and a video (or a file) together; a carousel and a list together; a file with anything else at all; a button on its own, with no text, image or video to attach it to; a button with no `caption`; a completely empty content object. `ttl` may accompany any of the working combinations.\n\nOnly fields you actually fill in are sent on; empty strings, empty objects and empty lists count as not set. Keys are snake_case, and the camelCase spelling noted per field also works.\n","properties":{"text":{"type":"string"},"media_url":{"type":"string","format":"uri","description":"Image URL. Also accepted as `mediaUrl`."},"video":{"type":"object","description":"A video. This is an object, not a plain URL string.","properties":{"media_url":{"type":"string","format":"uri","description":"Video URL. Also accepted as `mediaUrl`."},"thumbnail":{"type":"string","format":"uri"}}},"file":{"type":"object","description":"A file. This is an object, not a plain URL string. A file must be sent on its own - no text, button, image or video alongside it.\n","properties":{"media_url":{"type":"string","format":"uri","description":"File URL. Also accepted as `mediaUrl`."},"file_name":{"type":"string","description":"Also accepted as `fileName`."}}},"button":{"type":"object","required":["caption"],"description":"A button needs text, an image or a video alongside it, and it must have a caption.\n","properties":{"caption":{"type":"string","description":"The button label. Required."},"action":{"type":"string","description":"What the button opens - an `https://` or `viber://` link. Note the key is `action`; a `url` key is not supported and is ignored.\n"}}},"carousel":{"type":"object","description":"A carousel of cards. Send it on its own or with text - not with an image, video, file, button or list.\n","properties":{"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"image_url":{"type":"string","format":"uri","description":"Also accepted as `imageUrl`."},"primary_button":{"$ref":"#/components/schemas/CarouselButton"},"secondary_button":{"$ref":"#/components/schemas/CarouselButton"}}}}}},"list":{"type":"object","description":"A survey list. Send it on its own or with text - not with an image, video, file, button or carousel. `survey.options` must have at least one option.\n","properties":{"survey":{"type":"object","properties":{"options":{"type":"array","minItems":1,"items":{"type":"string"}}}}}},"ttl":{"type":"integer","description":"How long the message stays valid, in seconds."},"type":{"type":"string","description":"Accepted and ignored on Viber. It only matters if you send the same object to the SMS channel, where `\"text\"` marks it as convertible to plain text.\n"},"message_type":{"type":"string","description":"Accepted and ignored. Also accepted as `messageType`."}}},"CarouselButton":{"type":"object","description":"A button on a carousel card. The containing keys are also accepted as `primaryButton` / `secondaryButton`.\n","properties":{"label":{"type":"string"},"action_url":{"type":"string","format":"uri","description":"Also accepted as `actionUrl`."}}}}}}
```

## The ViberContent object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"ViberContent":{"type":"object","description":"Viber message content. Not every combination of fields is a valid Viber message, so the ones that work are listed here in full. Anything else is rejected with `UNSUPPORTED_CONTENT`. There is a ready-made example of each under **Request samples** on both send endpoints.\n\n**These work:**\n\n| Content | With text | With a button | |---|---|---| | `text` | - | yes | | `media_url` (image) | yes | yes | | `video` | yes | yes | | `file` | no | no | | `carousel` | yes | no | | `list` | yes | no |\n\n**These do not:** an image and a video (or a file) together; a carousel and a list together; a file with anything else at all; a button on its own, with no text, image or video to attach it to; a button with no `caption`; a completely empty content object. `ttl` may accompany any of the working combinations.\n\nOnly fields you actually fill in are sent on; empty strings, empty objects and empty lists count as not set. Keys are snake_case, and the camelCase spelling noted per field also works.\n","properties":{"text":{"type":"string"},"media_url":{"type":"string","format":"uri","description":"Image URL. Also accepted as `mediaUrl`."},"video":{"type":"object","description":"A video. This is an object, not a plain URL string.","properties":{"media_url":{"type":"string","format":"uri","description":"Video URL. Also accepted as `mediaUrl`."},"thumbnail":{"type":"string","format":"uri"}}},"file":{"type":"object","description":"A file. This is an object, not a plain URL string. A file must be sent on its own - no text, button, image or video alongside it.\n","properties":{"media_url":{"type":"string","format":"uri","description":"File URL. Also accepted as `mediaUrl`."},"file_name":{"type":"string","description":"Also accepted as `fileName`."}}},"button":{"type":"object","required":["caption"],"description":"A button needs text, an image or a video alongside it, and it must have a caption.\n","properties":{"caption":{"type":"string","description":"The button label. Required."},"action":{"type":"string","description":"What the button opens - an `https://` or `viber://` link. Note the key is `action`; a `url` key is not supported and is ignored.\n"}}},"carousel":{"type":"object","description":"A carousel of cards. Send it on its own or with text - not with an image, video, file, button or list.\n","properties":{"items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"image_url":{"type":"string","format":"uri","description":"Also accepted as `imageUrl`."},"primary_button":{"$ref":"#/components/schemas/CarouselButton"},"secondary_button":{"$ref":"#/components/schemas/CarouselButton"}}}}}},"list":{"type":"object","description":"A survey list. Send it on its own or with text - not with an image, video, file, button or carousel. `survey.options` must have at least one option.\n","properties":{"survey":{"type":"object","properties":{"options":{"type":"array","minItems":1,"items":{"type":"string"}}}}}},"ttl":{"type":"integer","description":"How long the message stays valid, in seconds."},"type":{"type":"string","description":"Accepted and ignored on Viber. It only matters if you send the same object to the SMS channel, where `\"text\"` marks it as convertible to plain text.\n"},"message_type":{"type":"string","description":"Accepted and ignored. Also accepted as `messageType`."}}},"CarouselButton":{"type":"object","description":"A button on a carousel card. The containing keys are also accepted as `primaryButton` / `secondaryButton`.\n","properties":{"label":{"type":"string"},"action_url":{"type":"string","format":"uri","description":"Also accepted as `actionUrl`."}}}}}}
```

## The CarouselButton object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"CarouselButton":{"type":"object","description":"A button on a carousel card. The containing keys are also accepted as `primaryButton` / `secondaryButton`.\n","properties":{"label":{"type":"string"},"action_url":{"type":"string","format":"uri","description":"Also accepted as `actionUrl`."}}}}}}
```

## The ErrorEntry object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"ErrorEntry":{"type":"object","properties":{"property":{"type":"string","description":"The request field that is wrong."},"error":{"type":"string","description":"What is wrong with it."}}}}}}
```

## The Problem object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"Problem":{"type":"object","description":"Every error, in one shape - `application/problem+json` (RFC 9457). There is not a different body per kind of failure, so you only need one parser.\n","required":["title","status","code"],"properties":{"title":{"type":"string","description":"Short human-readable summary of what went wrong. Meant for your logs, not for branching on - the wording may change.\n"},"status":{"type":"integer","description":"The HTTP status, repeated here so the body stands on its own."},"code":{"type":"string","description":"Stable machine-readable code. **This is the one to branch on** - it never changes for a given condition, while the status and title may be refined.\n","enum":["VALIDATION_FAILED","UNAUTHORIZED","OUT_OF_BALANCE","CLIENT_PRICE_NOT_FOUND","IP_NOT_ALLOWED","DISABLED_CONNECTION","DISABLED_CLIENT","CLIENT_ARCHIVED","DISABLED_ACCOUNT","DISABLED_PRODUCT","DISABLED_CLIENT_PRODUCT","CHANNEL_DISABLED","INVALID_SENDER","DESTINATION_COUNTRY_FORBIDDEN","UNKNOWN_CHANNEL","CHANNEL_NOT_CONFIGURED","CLIENT_PRODUCT_DOES_NOT_EXIST","PROFILE_NOT_FOUND","UNKNOWN_BRAND","NO_DNS_CONFIGURED","NOT_FOUND","METHOD_NOT_ALLOWED","UNSUPPORTED_MEDIA_TYPE","PAYLOAD_TOO_LARGE","UNSUPPORTED_CONTENT","REJECTED","TOO_MANY_REQUESTS","NO_ROUTES","INTERNAL_ERROR"]},"errors":{"type":"array","description":"Only on a `400`: one entry per offending field, so you can point at the exact problem rather than re-reading the whole request.\n","items":{"$ref":"#/components/schemas/ErrorEntry"}}}},"ErrorEntry":{"type":"object","properties":{"property":{"type":"string","description":"The request field that is wrong."},"error":{"type":"string","description":"What is wrong with it."}}}}}}
```

## The DeliveryReport object

```json
{"openapi":"3.0.3","info":{"title":"Channels API","version":"1.0"},"components":{"schemas":{"DeliveryReport":{"type":"object","description":"The delivery report we POST to your account's default webhook.","properties":{"type":{"type":"string","enum":["DLR"]},"message_id":{"type":"string","format":"uuid","description":"The `request_id` you got when the message was accepted."},"to":{"type":"string","description":"Recipient phone number."},"status":{"type":"string","enum":["DELIVERED","SEEN","UNDELIVERABLE"],"description":"`DELIVERED` and `UNDELIVERABLE` are final - the message is done, and every channel it could be tried on has been. `SEEN` is a read receipt and is not final; expect it in addition to, not instead of, a final report.\n"},"error":{"type":"string","description":"Result code - `000` for `DELIVERED` and `SEEN`, `001` for a generic failure, or a more specific code when the channel gives us one.\n"},"cost":{"type":"number","nullable":true,"description":"What this attempt actually charged, in your account currency - `0` if the message was never charged (e.g. an `UNDELIVERABLE` outcome on an account billed per delivery). May differ from the `cost` on the send response, which was only an indicative estimate for the first channel tried.\n"}}}}}}
```


