# International SMS

https://dev.wisecp.com/es/international-sms

The fifteen endpoints that manage international SMS sender name applications, country prices and module settings.

## Overview

Some countries insist the SMS sender name is approved in advance. The client applies with documents and you approve or refuse; the first six endpoints run that flow.

The rest is about the selling: which module sends, the cost and price per country, the margin, and clearing old records. Prices are kept in a single **primary currency**, and automatic pricing does not run until it is set.

## Reference

### Listing the Applications

get/api/v1/admin/products/sms/intl-origins

`Products/GetSmsIntlOrigins` admin paged

Returns the sender name applications clients opened, one per country.

Query parameters 3

searchstringSearches the records.

pageintDefaults to 1.

limitintDefaults to 25, maximum 100.

Response fields data[] — 11

idintRecord id.

origin_idintId of the domestic sender name it comes from.

origin_namestringThe sender name.

country_codestringThe country code. Two letters, lower case.

statusstring`waiting` is awaiting review, `active` was approved, `inactive` was refused.

status_messagestringThe message left on the decision.

clientobject 3 fieldsThe client who opened the request.

idintClient id.

full_namestringFirst and last name.

company_namestringCompany name.

attachmentsarray 4 fieldsThe documents the client uploaded.

sizeintThe file size in bytes.

file_namestringThe original name the client uploaded.

namestringThe name stored on the server.

file_pathstringWhere the file is kept.

created_atstring | nullWhen the request was opened.

approved_datestring | nullWhen it was approved.

rejected_datestring | nullWhen it was refused.

Meta 4

totalintTotal records matching the filter.

pageintThe page you are on.

limitintThe page size.

next_pageintThe next page. Zero means you are on the last one.

Errors 1

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/products/sms/intl-origins' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-origins', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-origins');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Products()->GetSmsIntlOrigins();

$waiting = array_filter(
    $response['data'],
    fn (array $r): bool => $r['status'] === 'waiting',
);
```

Response 200

```json
{
  "data": [
    {
      "id": 9,
      "origin_id": 1,
      "origin_name": "ACME",
      "country_code": "sv",
      "status": "waiting",
      "status_message": "",
      "client": { "id": 2, "full_name": "John Doe", "company_name": "" },
      "attachments": [
        {
          "size": 255435,
          "file_name": "licence.jpg",
          "name": "215d8151c44f2d058eee5e5.jpg",
          "file_path": "215d8151c44f2d058eee5e5.jpg"
        }
      ],
      "created_at": "2026-03-09 11:52:45",
      "approved_date": null,
      "rejected_date": null
    }
  ],
  "meta": { "total": 2, "page": 1, "limit": 25, "next_page": 0 }
}
```

### Application Detail

get/api/v1/admin/products/sms/intl-origins/{id}

`Products/GetSmsIntlOrigin` admin

Returns one application. The schema is the same as a list item.

Response fields data — 11

idintRecord id.

origin_idintId of the domestic sender name it comes from.

origin_namestringThe sender name.

country_codestringThe country code. Two letters, lower case.

statusstring`waiting` is awaiting review, `active` was approved, `inactive` was refused.

status_messagestringThe message left on the decision.

clientobject 3 fieldsThe client who opened the request.

idintClient id.

full_namestringFirst and last name.

company_namestringCompany name.

attachmentsarray 4 fieldsThe documents the client uploaded.

sizeintThe file size in bytes.

file_namestringThe original name the client uploaded.

namestringThe name stored on the server.

file_pathstringWhere the file is kept.

created_atstring | nullWhen the request was opened.

approved_datestring | nullWhen it was approved.

rejected_datestring | nullWhen it was refused.

Errors 2

not_found404No such record.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/products/sms/intl-origins/9' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-origins/9', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-origins/9');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Products()->GetSmsIntlOrigin(['id' => 9]);
```

### Settling an Application

put/api/v1/admin/products/sms/intl-origins/{id}/status

`Products/SetSmsIntlOriginStatus` admin

Approves or refuses the application.

Body 2

actionstringrequired`active` approves, `inactive` refuses.

reasonstringThe message to leave on the decision. Canned texts come from the reasons endpoint.

Response fields data

dataobjectThe application as it now stands. Same shape as the detail schema. Of the two decision dates, the one that no longer applies is cleared.

Errors 3

not_found404No such record.

invalid_action422The action is neither `active` nor `inactive`.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PUT 'https://panel.example.com/api/v1/admin/products/sms/intl-origins/9/status' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"action":"inactive","reason":"Documents missing"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-origins/9/status', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ action: 'inactive', reason: 'Documents missing' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-origins/9/status');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'action' => 'inactive',
        'reason' => 'Documents missing',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// Take the canned reason from the template list so the client always sees the same text.
$reasons = Api::Products()->GetSmsReasons([], ['group' => 'international-sms'])['data'];

Api::Products()->SetSmsIntlOriginStatus([
    'id'     => 9,
    'action' => 'inactive',
    'reason' => $reasons['en'][0]['description'] ?? '',
]);
```

### Settling in Bulk

post/api/v1/admin/products/sms/intl-origins/bulk

`Products/BulkSmsIntlOrigins` admin no reason

Approves or refuses several applications in one call.

Body 2

idsint[]requiredThe application ids.

actionstringrequired`active` or `inactive`.

Response fields data — 2

updatedint[]The ids whose status changed.

actionstringThe status that was applied.

Errors 3

ids_required422`ids` was empty.

invalid_action422The action is neither `active` nor `inactive`.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/products/sms/intl-origins/bulk' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"ids":[9,10],"action":"active"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-origins/bulk', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ ids: [9, 10], action: 'active' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-origins/bulk');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode(['ids' => [9, 10], 'action' => 'active']),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The bulk endpoint has NO reason field: settle one by one when a refusal message is needed.
Api::Products()->BulkSmsIntlOrigins([
    'ids'    => [9, 10],
    'action' => 'active',
]);
```

### Deleting an Application

delete/api/v1/admin/products/sms/intl-origins/{id}

`Products/DeleteSmsIntlOrigin` admin documents go too

Deletes the application and the documents uploaded with it.

Response fields data — 2

deletedboolWhether the delete succeeded.

idintId of the deleted application.

Errors 2

not_found404No such record.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X DELETE 'https://panel.example.com/api/v1/admin/products/sms/intl-origins/9' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-origins/9', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-origins/9');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Products()->DeleteSmsIntlOrigin(['id' => 9]);
```

### A Delivery Report

get/api/v1/admin/products/sms/intl-reports/{id}

`Products/GetSmsIntlReport` admin asks the module

Asks the provider for the live delivery state of a sent message.

Response fields data — 5

modulestringThe SMS module that produced the report.

sendingarrayRecipients still in flight. The row shape belongs to the module, so it differs from one provider to the next.

deliveredarrayRecipients confirmed delivered.

failedarrayRecipients that failed.

total_recipientsintThe count the module reports. Read this one rather than the lengths of the three arrays; they can differ.

Errors 5

not_found404No such report.

no_module422There is no SMS module for this report.

not_supported422The module does not support delivery reports.

report_failed422The provider did not answer.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/products/sms/intl-reports/501' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-reports/501', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-reports/501');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The report is produced by asking the provider: it can be slow and depends on module support.
$response = Api::Products()->GetSmsIntlReport(['id' => 501]);
```

### Listing the Refusal Reasons

get/api/v1/admin/products/sms/reasons

`Products/GetSmsReasons` admin

Returns the canned texts used when refusing an application, one set per language.

Query parameters 1

groupstringWhich channel: `sms` or `international-sms`. It defaults to `sms`, so forgetting the parameter gives you the domestic list.

Response fields data

dataobjectA map from language code to a list of reasons. Each carries a title and a description.

Errors 1

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -G 'https://panel.example.com/api/v1/admin/products/sms/reasons' \
  -H "Authorization: Bearer $API_KEY" \
  -d group=international-sms
```

```javascript
const url = new URL('https://panel.example.com/api/v1/admin/products/sms/reasons');
url.searchParams.set('group', 'international-sms');

const res  = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } });
const body = await res.json();
```

```php
$url = 'https://panel.example.com/api/v1/admin/products/sms/reasons?' . http_build_query(['group' => 'international-sms']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Products()->GetSmsReasons([], ['group' => 'international-sms']);
```

### Adding a Refusal Reason

post/api/v1/admin/products/sms/reasons

`Products/AddSmsReason` admin 201

Adds a canned refusal text to one language.

Body 2

langstringrequiredWhich language the text goes into.

reasonstringrequiredThe reason text. The title is built from its first fifty characters.

Query parameters 1

groupstringWhich channel: `sms` or `international-sms`. It defaults to `sms`, so forgetting the parameter gives you the domestic list.

Response fields data

dataobjectThe whole reason set after the write, returned with `201`. Same shape as the listing: one key per installed language, each holding its own list. A language with no reasons comes back as an empty array.

Errors 2

reason_required422The language or the text was empty.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/products/sms/reasons?group=international-sms' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"lang":"en","reason":"Please upload a valid trade licence."}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/reasons?group=international-sms', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    lang: 'en',
    reason: 'Please upload a valid trade licence.',
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/reasons?group=international-sms');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'lang'   => 'en',
        'reason' => 'Please upload a valid trade licence.',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Products()->AddSmsReason(
    ['lang' => 'en', 'reason' => 'Please upload a valid trade licence.'],
    ['group' => 'international-sms'],
);
```

### Deleting a Refusal Reason

delete/api/v1/admin/products/sms/reasons/{index}

`Products/DeleteSmsReason` admin deleted by position

Deletes a reason from one language by its position in the list.

Query parameters 2

langstringrequiredWhich language's list to delete from.

groupstringWhich channel: `sms` or `international-sms`. It defaults to `sms`, so forgetting the parameter gives you the domestic list.

Response fields data

dataobjectThe whole reason set after the delete. Same shape as the listing. The list is renumbered, so every reason below the deleted one moves up a position.

Errors 3

lang_required422`lang` was not given.

not_found404There is no reason at that position.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X DELETE -G 'https://panel.example.com/api/v1/admin/products/sms/reasons/0' \
  -H "Authorization: Bearer $API_KEY" \
  -d lang=en \
  -d group=international-sms
```

```javascript
const url = new URL('https://panel.example.com/api/v1/admin/products/sms/reasons/0');
url.searchParams.set('lang', 'en');
url.searchParams.set('group', 'international-sms');

const res = await fetch(url, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$url = 'https://panel.example.com/api/v1/admin/products/sms/reasons/0?' . http_build_query([
    'lang'  => 'en',
    'group' => 'international-sms',
]);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// Positions SHIFT after a delete: going back to front is the safe order for several.
foreach ([2, 1] as $index)
    Api::Products()->DeleteSmsReason(['index' => $index], ['lang' => 'en']);
```

### Reading the Settings

get/api/v1/admin/products/sms/intl-settings

`Products/GetSmsIntlSettings` admin

Returns the module, pricing and pre-registration settings for international SMS.

Response fields data — 5

active_modulestringThe SMS module in use. `none` when none is chosen.

cron_statusboolWhether the job that refreshes prices is on.

primary_currencyintCurrency id the prices are kept in.

profit_ratefloatThe profit margin added on top of cost.

pre_register_countriesstring[]The countries where the sender name has to be approved in advance.

Errors 1

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/products/sms/intl-settings' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-settings', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Products()->GetSmsIntlSettings();
```

### Writing the Settings

put/api/v1/admin/products/sms/intl-settings

`Products/SetSmsIntlSettings` admin the margin is its own branch

Sets the module, the pricing job and the pre-registration countries, or changes only the margin.

Body 5

marginfloatThe profit margin. Sending this field ignores the others and reprices.

active_modulestringThe SMS module to use.

cron_statusboolTurns on the job that refreshes prices.

primary_currencyintThe currency the prices are kept in.

countries_pre_registerstring[]The countries where the sender name needs approval in advance.

Response fields data

dataobjectThe settings as they now stand. Same shape as reading them.

Errors 3

module_unsupported422The job was asked for but the module cannot fetch prices.

update_failed422The setting could not be stored.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PUT 'https://panel.example.com/api/v1/admin/products/sms/intl-settings' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"active_module":"Twilio","cron_status":true,"primary_currency":1}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-settings', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    active_module: 'Twilio',
    cron_status: true,
    primary_currency: 1,
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-settings');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'active_module'    => 'Twilio',
        'cron_status'      => true,
        'primary_currency' => 1,
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// With 'margin' in the body the OTHER fields are not read - make them two requests.
Api::Products()->SetSmsIntlSettings(['active_module' => 'Twilio']);
Api::Products()->SetSmsIntlSettings(['margin' => 20]);
```

### Reading the Prices

get/api/v1/admin/products/sms/intl-pricing

`Products/GetSmsIntlPricing` admin

Returns the cost and the selling price for each country.

Query parameters 1

primary_currencyintUses this instead of the currency in the settings.

Response fields data[] — 5

country_codestringThe country code. UPPER case here, lower case on the application records.

costfloatWhat the provider charges you.

amountfloatWhat the client is charged.

cidintCurrency id.

statusboolWhether sending to that country is open.

Errors 1

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl 'https://panel.example.com/api/v1/admin/products/sms/intl-pricing' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res  = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-pricing', {
  headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-pricing');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
$response = Api::Products()->GetSmsIntlPricing();
```

### Writing the Prices

put/api/v1/admin/products/sms/intl-pricing

`Products/SetSmsIntlPricing` admin

Writes the cost and the price per country by hand.

Body 1

valuesobjectrequiredA map from country code to a price object carrying the cost, the amount, the currency and whether sending is open. Only the countries you send change.

Response fields data — 1

updatedintHow many countries were updated.

Errors 2

values_required422`values` was empty.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X PUT 'https://panel.example.com/api/v1/admin/products/sms/intl-pricing' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"values":{"US":{"cost":0.01,"amount":0.02,"cid":1,"status":true}}}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-pricing', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    values: {
      US: { cost: 0.01, amount: 0.02, cid: 1, status: true },
    },
  }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-pricing');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'values' => [
            'US' => ['cost' => 0.01, 'amount' => 0.02, 'cid' => 1, 'status' => true],
        ],
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The country code goes in UPPER case; do not mix it with the lower-case code on applications.
Api::Products()->SetSmsIntlPricing([
    'values' => [
        'US' => ['cost' => 0.01, 'amount' => 0.02, 'cid' => 1, 'status' => true],
    ],
]);
```

### Pulling Prices from the Module

post/api/v1/admin/products/sms/intl-pricing/auto

`Products/AutoDefineSmsIntlPricing` admin overwrites hand-set prices

Pulls the country prices from the provider and writes them with the margin applied.

Body —

——No body is needed; send an empty one. The module, the currency and the margin all come from the international SMS settings.

Response fields data — 1

statusstringThe outcome of the run.

Errors 5

no_module422No SMS module is selected.

module_unsupported422The module does not support fetching prices.

no_primary_currency422The primary currency is not set.

auto_define_failed422The prices could not be fetched.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/products/sms/intl-pricing/auto' \
  -H "Authorization: Bearer $API_KEY"
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/intl-pricing/auto', {
  method: 'POST',
  headers: { Authorization: `Bearer ${apiKey}` },
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/intl-pricing/auto');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . $apiKey],
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// The endpoint has three preconditions: a module is chosen, it can fetch prices, a currency is set.
$settings = Api::Products()->GetSmsIntlSettings()['data'];

if ($settings['active_module'] !== 'none' && $settings['primary_currency'] > 0)
    Api::Products()->AutoDefineSmsIntlPricing();
```

### Clearing the Reports

post/api/v1/admin/products/sms/clear-reports

`Products/ClearSmsReports` admin cannot be undone

Deletes the SMS records sent on and before the date you give.

Body 2

datestringrequiredThe cut-off date. This date and everything before it goes.

typestringWhich channel: `domestic` or `international`. Defaults to `domestic`.

Response fields data — 3

clearedboolWhether the clear ran.

beforestringThe cut-off date that was used.

typestringThe channel that was cleared.

Errors 2

invalid_date422The date is missing or invalid.

insufficient_scope403The key lacks the required scope.

Request cURL JavaScript PHP (HTTP) PHP (Internal)

```bash
curl -X POST 'https://panel.example.com/api/v1/admin/products/sms/clear-reports' \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"date":"2026-01-01","type":"international"}'
```

```javascript
const res = await fetch('https://panel.example.com/api/v1/admin/products/sms/clear-reports', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ date: '2026-01-01', type: 'international' }),
});

const body = await res.json();
```

```php
$ch = curl_init('https://panel.example.com/api/v1/admin/products/sms/clear-reports');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'date' => '2026-01-01',
        'type' => 'international',
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
```

```php
// Leave the channel out and the DOMESTIC records go; ask for international explicitly.
Api::Products()->ClearSmsReports([
    'date' => '2026-01-01',
    'type' => 'international',
]);
```

## Pitfalls

> **The country code case differs between endpoints**
> 
> The application records return the country code in **lower** case while the pricing endpoints expect and return **upper** case. Code that matches the two without normalising the case finds no country at all, and does so quietly.

> **The margin field ignores the others**
> 
> With `margin` in the body only the margin branch runs; the module, the currency and the country list are **not read**. To change both, send two separate requests.

> **Auto pricing overwrites hand-set prices**
> 
> Pulling prices from the module writes over the country prices you set by hand. If you priced a few countries specially you have to enter them again after this call, and with the pricing job on the same overwrite happens **on a schedule**.

> **The bulk decision carries no reason**
> 
> The bulk endpoint only changes the status; there is no field for a refusal message. If the client is meant to see why they were refused, the applications have to be settled one at a time.

> **Reason positions shift after a delete**
> 
> Reasons are deleted by their position in the list, not by an id. Deleting one shifts everything after it down by one, so when deleting several go **back to front** or you will remove the wrong text.

## Related Articles

- [Product Endpoints](https://dev.wisecp.com/en/product-endpoints)
- [Domain Pricing and Settings](https://dev.wisecp.com/en/domain-pricing-settings)
