> ## Documentation Index
> Fetch the complete documentation index at: https://developers.nlpearl.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Send SMS Node

export const SMS_COUNTRIES = [{
  code: 1,
  iso: "US",
  name: "United States",
  rate: 1
}, {
  code: 7,
  iso: "RU",
  name: "Russia",
  rate: 76
}, {
  code: 20,
  iso: "EG",
  name: "Egypt",
  rate: 40
}, {
  code: 27,
  iso: "ZA",
  name: "South Africa",
  rate: 14
}, {
  code: 30,
  iso: "GR",
  name: "Greece",
  rate: 7
}, {
  code: 31,
  iso: "NL",
  name: "Netherlands",
  rate: 12
}, {
  code: 32,
  iso: "BE",
  name: "Belgium",
  rate: 12
}, {
  code: 33,
  iso: "FR",
  name: "France",
  rate: 8
}, {
  code: 34,
  iso: "ES",
  name: "Spain",
  rate: 9
}, {
  code: 36,
  iso: "HU",
  name: "Hungary",
  rate: 10
}, {
  code: 39,
  iso: "IT",
  name: "Italy",
  rate: 10
}, {
  code: 40,
  iso: "RO",
  name: "Romania",
  rate: 8
}, {
  code: 41,
  iso: "CH",
  name: "Switzerland",
  rate: 8
}, {
  code: 43,
  iso: "AT",
  name: "Austria",
  rate: 10
}, {
  code: 44,
  iso: "GB",
  name: "United Kingdom",
  rate: 6
}, {
  code: 45,
  iso: "DK",
  name: "Denmark",
  rate: 6
}, {
  code: 46,
  iso: "SE",
  name: "Sweden",
  rate: 12
}, {
  code: 47,
  iso: "NO",
  name: "Norway",
  rate: 7
}, {
  code: 48,
  iso: "PL",
  name: "Poland",
  rate: 5
}, {
  code: 49,
  iso: "DE",
  name: "Germany",
  rate: 12
}, {
  code: 51,
  iso: "PE",
  name: "Peru",
  rate: 25
}, {
  code: 52,
  iso: "MX",
  name: "Mexico",
  rate: 19
}, {
  code: 54,
  iso: "AR",
  name: "Argentina",
  rate: 11
}, {
  code: 55,
  iso: "BR",
  name: "Brazil",
  rate: 7
}, {
  code: 56,
  iso: "CL",
  name: "Chile",
  rate: 8
}, {
  code: 57,
  iso: "CO",
  name: "Colombia",
  rate: 6
}, {
  code: 58,
  iso: "VE",
  name: "Venezuela",
  rate: 23
}, {
  code: 60,
  iso: "MY",
  name: "Malaysia",
  rate: 33
}, {
  code: 61,
  iso: "AU",
  name: "Australia",
  rate: 6
}, {
  code: 62,
  iso: "ID",
  name: "Indonesia",
  rate: 45
}, {
  code: 63,
  iso: "PH",
  name: "Philippines",
  rate: 25
}, {
  code: 64,
  iso: "NZ",
  name: "New Zealand",
  rate: 12
}, {
  code: 65,
  iso: "SG",
  name: "Singapore",
  rate: 7
}, {
  code: 66,
  iso: "TH",
  name: "Thailand",
  rate: 4
}, {
  code: 81,
  iso: "JP",
  name: "Japan",
  rate: 9
}, {
  code: 82,
  iso: "KR",
  name: "South Korea",
  rate: 6
}, {
  code: 84,
  iso: "VN",
  name: "Vietnam",
  rate: 29
}, {
  code: 86,
  iso: "CN",
  name: "China",
  rate: 11
}, {
  code: 90,
  iso: "TR",
  name: "Turkey",
  rate: 4
}, {
  code: 91,
  iso: "IN",
  name: "India",
  rate: 9
}, {
  code: 92,
  iso: "PK",
  name: "Pakistan",
  rate: 48
}, {
  code: 93,
  iso: "AF",
  name: "Afghanistan",
  rate: 45
}, {
  code: 94,
  iso: "LK",
  name: "Sri Lanka",
  rate: 42
}, {
  code: 95,
  iso: "MM",
  name: "Myanmar",
  rate: 42
}, {
  code: 211,
  iso: "SS",
  name: "South Sudan",
  rate: 24
}, {
  code: 212,
  iso: "MA",
  name: "Morocco",
  rate: 23
}, {
  code: 213,
  iso: "DZ",
  name: "Algeria",
  rate: 28
}, {
  code: 216,
  iso: "TN",
  name: "Tunisia",
  rate: 54
}, {
  code: 218,
  iso: "LY",
  name: "Libya",
  rate: 45
}, {
  code: 220,
  iso: "GM",
  name: "Gambia",
  rate: 27
}, {
  code: 221,
  iso: "SN",
  name: "Senegal",
  rate: 56
}, {
  code: 222,
  iso: "MR",
  name: "Mauritania",
  rate: 37
}, {
  code: 223,
  iso: "ML",
  name: "Mali",
  rate: 35
}, {
  code: 224,
  iso: "GN",
  name: "Guinea",
  rate: 28
}, {
  code: 225,
  iso: "CI",
  name: "Cote d'Ivoire",
  rate: 44
}, {
  code: 226,
  iso: "BF",
  name: "Burkina Faso",
  rate: 23
}, {
  code: 227,
  iso: "NE",
  name: "Niger",
  rate: 37
}, {
  code: 228,
  iso: "TG",
  name: "Togo",
  rate: 45
}, {
  code: 229,
  iso: "BJ",
  name: "Benin",
  rate: 30
}, {
  code: 230,
  iso: "MU",
  name: "Mauritius",
  rate: 27
}, {
  code: 231,
  iso: "LR",
  name: "Liberia",
  rate: 25
}, {
  code: 232,
  iso: "SL",
  name: "Sierra Leone",
  rate: 79
}, {
  code: 233,
  iso: "GH",
  name: "Ghana",
  rate: 38
}, {
  code: 234,
  iso: "NG",
  name: "Nigeria",
  rate: 39
}, {
  code: 235,
  iso: "TD",
  name: "Chad",
  rate: 35
}, {
  code: 236,
  iso: "CF",
  name: "Central African Republic",
  rate: 46
}, {
  code: 237,
  iso: "CM",
  name: "Cameroon",
  rate: 32
}, {
  code: 238,
  iso: "CV",
  name: "Cape Verde",
  rate: 23
}, {
  code: 239,
  iso: "ST",
  name: "Sao Tome and Principe",
  rate: 14
}, {
  code: 240,
  iso: "GQ",
  name: "Equatorial Guinea",
  rate: 28
}, {
  code: 241,
  iso: "GA",
  name: "Gabon",
  rate: 32
}, {
  code: 242,
  iso: "CG",
  name: "Republic of the Congo",
  rate: 34
}, {
  code: 243,
  iso: "CD",
  name: "DR Congo",
  rate: 26
}, {
  code: 244,
  iso: "AO",
  name: "Angola",
  rate: 31
}, {
  code: 245,
  iso: "GW",
  name: "Guinea-Bissau",
  rate: 48
}, {
  code: 248,
  iso: "SC",
  name: "Seychelles",
  rate: 31
}, {
  code: 249,
  iso: "SD",
  name: "Sudan",
  rate: 48
}, {
  code: 250,
  iso: "RW",
  name: "Rwanda",
  rate: 33
}, {
  code: 251,
  iso: "ET",
  name: "Ethiopia",
  rate: 35
}, {
  code: 252,
  iso: "SO",
  name: "Somalia",
  rate: 38
}, {
  code: 253,
  iso: "DJ",
  name: "Djibouti",
  rate: 17
}, {
  code: 254,
  iso: "KE",
  name: "Kenya",
  rate: 24
}, {
  code: 255,
  iso: "TZ",
  name: "Tanzania",
  rate: 44
}, {
  code: 256,
  iso: "UG",
  name: "Uganda",
  rate: 33
}, {
  code: 257,
  iso: "BI",
  name: "Burundi",
  rate: 47
}, {
  code: 258,
  iso: "MZ",
  name: "Mozambique",
  rate: 42
}, {
  code: 260,
  iso: "ZM",
  name: "Zambia",
  rate: 40
}, {
  code: 261,
  iso: "MG",
  name: "Madagascar",
  rate: 53
}, {
  code: 262,
  iso: "RE",
  name: "Reunion",
  rate: 20
}, {
  code: 263,
  iso: "ZW",
  name: "Zimbabwe",
  rate: 25
}, {
  code: 264,
  iso: "NA",
  name: "Namibia",
  rate: 11
}, {
  code: 265,
  iso: "MW",
  name: "Malawi",
  rate: 34
}, {
  code: 266,
  iso: "LS",
  name: "Lesotho",
  rate: 42
}, {
  code: 267,
  iso: "BW",
  name: "Botswana",
  rate: 16
}, {
  code: 268,
  iso: "SZ",
  name: "Eswatini",
  rate: 27
}, {
  code: 269,
  iso: "KM",
  name: "Comoros",
  rate: 42
}, {
  code: 291,
  iso: "ER",
  name: "Eritrea",
  rate: 13
}, {
  code: 297,
  iso: "AW",
  name: "Aruba",
  rate: 28
}, {
  code: 298,
  iso: "FO",
  name: "Faroe Islands",
  rate: 8
}, {
  code: 299,
  iso: "GL",
  name: "Greenland",
  rate: 5
}, {
  code: 350,
  iso: "GI",
  name: "Gibraltar",
  rate: 11
}, {
  code: 351,
  iso: "PT",
  name: "Portugal",
  rate: 6
}, {
  code: 352,
  iso: "LU",
  name: "Luxembourg",
  rate: 9
}, {
  code: 353,
  iso: "IE",
  name: "Ireland",
  rate: 8
}, {
  code: 354,
  iso: "IS",
  name: "Iceland",
  rate: 8
}, {
  code: 355,
  iso: "AL",
  name: "Albania",
  rate: 12
}, {
  code: 356,
  iso: "MT",
  name: "Malta",
  rate: 7
}, {
  code: 357,
  iso: "CY",
  name: "Cyprus",
  rate: 9
}, {
  code: 358,
  iso: "FI",
  name: "Finland",
  rate: 9
}, {
  code: 359,
  iso: "BG",
  name: "Bulgaria",
  rate: 15
}, {
  code: 370,
  iso: "LT",
  name: "Lithuania",
  rate: 9
}, {
  code: 371,
  iso: "LV",
  name: "Latvia",
  rate: 9
}, {
  code: 372,
  iso: "EE",
  name: "Estonia",
  rate: 10
}, {
  code: 373,
  iso: "MD",
  name: "Moldova",
  rate: 15
}, {
  code: 374,
  iso: "AM",
  name: "Armenia",
  rate: 30
}, {
  code: 375,
  iso: "BY",
  name: "Belarus",
  rate: 26
}, {
  code: 376,
  iso: "AD",
  name: "Andorra",
  rate: 15
}, {
  code: 377,
  iso: "MC",
  name: "Monaco",
  rate: 19
}, {
  code: 378,
  iso: "SM",
  name: "San Marino",
  rate: 13
}, {
  code: 380,
  iso: "UA",
  name: "Ukraine",
  rate: 23
}, {
  code: 381,
  iso: "RS",
  name: "Serbia",
  rate: 41
}, {
  code: 382,
  iso: "ME",
  name: "Montenegro",
  rate: 18
}, {
  code: 385,
  iso: "HR",
  name: "Croatia",
  rate: 14
}, {
  code: 386,
  iso: "SI",
  name: "Slovenia",
  rate: 21
}, {
  code: 387,
  iso: "BA",
  name: "Bosnia and Herzegovina",
  rate: 52
}, {
  code: 389,
  iso: "MK",
  name: "North Macedonia",
  rate: 21
}, {
  code: 420,
  iso: "CZ",
  name: "Czech Republic",
  rate: 8
}, {
  code: 421,
  iso: "SK",
  name: "Slovakia",
  rate: 9
}, {
  code: 423,
  iso: "LI",
  name: "Liechtenstein",
  rate: 4
}, {
  code: 500,
  iso: "FK",
  name: "Falkland Islands",
  rate: 17
}, {
  code: 501,
  iso: "BZ",
  name: "Belize",
  rate: 30
}, {
  code: 502,
  iso: "GT",
  name: "Guatemala",
  rate: 25
}, {
  code: 503,
  iso: "SV",
  name: "El Salvador",
  rate: 30
}, {
  code: 504,
  iso: "HN",
  name: "Honduras",
  rate: 33
}, {
  code: 505,
  iso: "NI",
  name: "Nicaragua",
  rate: 16
}, {
  code: 506,
  iso: "CR",
  name: "Costa Rica",
  rate: 9
}, {
  code: 507,
  iso: "PA",
  name: "Panama",
  rate: 19
}, {
  code: 508,
  iso: "PM",
  name: "Saint Pierre and Miquelon",
  rate: 16
}, {
  code: 509,
  iso: "HT",
  name: "Haiti",
  rate: 30
}, {
  code: 590,
  iso: "GP",
  name: "Guadeloupe",
  rate: 23
}, {
  code: 591,
  iso: "BO",
  name: "Bolivia",
  rate: 23
}, {
  code: 592,
  iso: "GY",
  name: "Guyana",
  rate: 34
}, {
  code: 593,
  iso: "EC",
  name: "Ecuador",
  rate: 34
}, {
  code: 594,
  iso: "GF",
  name: "French Guiana",
  rate: 19
}, {
  code: 595,
  iso: "PY",
  name: "Paraguay",
  rate: 13
}, {
  code: 596,
  iso: "MQ",
  name: "Martinique",
  rate: 19
}, {
  code: 597,
  iso: "SR",
  name: "Suriname",
  rate: 32
}, {
  code: 598,
  iso: "UY",
  name: "Uruguay",
  rate: 9
}, {
  code: 670,
  iso: "TL",
  name: "Timor-Leste",
  rate: 26
}, {
  code: 672,
  iso: "NF",
  name: "Norfolk Island",
  rate: 12
}, {
  code: 673,
  iso: "BN",
  name: "Brunei",
  rate: 7
}, {
  code: 675,
  iso: "PG",
  name: "Papua New Guinea",
  rate: 76
}, {
  code: 676,
  iso: "TO",
  name: "Tonga",
  rate: 22
}, {
  code: 677,
  iso: "SB",
  name: "Solomon Islands",
  rate: 13
}, {
  code: 678,
  iso: "VU",
  name: "Vanuatu",
  rate: 22
}, {
  code: 679,
  iso: "FJ",
  name: "Fiji",
  rate: 22
}, {
  code: 680,
  iso: "PW",
  name: "Palau",
  rate: 24
}, {
  code: 681,
  iso: "WF",
  name: "Wallis and Futuna",
  rate: 11
}, {
  code: 682,
  iso: "CK",
  name: "Cook Islands",
  rate: 14
}, {
  code: 683,
  iso: "NU",
  name: "Niue",
  rate: 24
}, {
  code: 685,
  iso: "WS",
  name: "Samoa",
  rate: 24
}, {
  code: 686,
  iso: "KI",
  name: "Kiribati",
  rate: 15
}, {
  code: 687,
  iso: "NC",
  name: "New Caledonia",
  rate: 18
}, {
  code: 688,
  iso: "TV",
  name: "Tuvalu",
  rate: 30
}, {
  code: 689,
  iso: "PF",
  name: "French Polynesia",
  rate: 18
}, {
  code: 691,
  iso: "FM",
  name: "Micronesia",
  rate: 8
}, {
  code: 692,
  iso: "MH",
  name: "Marshall Islands",
  rate: 16
}, {
  code: 852,
  iso: "HK",
  name: "Hong Kong",
  rate: 8
}, {
  code: 853,
  iso: "MO",
  name: "Macau",
  rate: 11
}, {
  code: 855,
  iso: "KH",
  name: "Cambodia",
  rate: 45
}, {
  code: 856,
  iso: "LA",
  name: "Laos",
  rate: 32
}, {
  code: 880,
  iso: "BD",
  name: "Bangladesh",
  rate: 60
}, {
  code: 886,
  iso: "TW",
  name: "Taiwan",
  rate: 9
}, {
  code: 960,
  iso: "MV",
  name: "Maldives",
  rate: 36
}, {
  code: 961,
  iso: "LB",
  name: "Lebanon",
  rate: 37
}, {
  code: 962,
  iso: "JO",
  name: "Jordan",
  rate: 39
}, {
  code: 964,
  iso: "IQ",
  name: "Iraq",
  rate: 45
}, {
  code: 965,
  iso: "KW",
  name: "Kuwait",
  rate: 32
}, {
  code: 966,
  iso: "SA",
  name: "Saudi Arabia",
  rate: 20
}, {
  code: 967,
  iso: "YE",
  name: "Yemen",
  rate: 30
}, {
  code: 968,
  iso: "OM",
  name: "Oman",
  rate: 22
}, {
  code: 971,
  iso: "AE",
  name: "United Arab Emirates",
  rate: 12
}, {
  code: 972,
  iso: "IL",
  name: "Israel",
  rate: 25
}, {
  code: 973,
  iso: "BH",
  name: "Bahrain",
  rate: 4
}, {
  code: 974,
  iso: "QA",
  name: "Qatar",
  rate: 27
}, {
  code: 975,
  iso: "BT",
  name: "Bhutan",
  rate: 41
}, {
  code: 976,
  iso: "MN",
  name: "Mongolia",
  rate: 30
}, {
  code: 977,
  iso: "NP",
  name: "Nepal",
  rate: 31
}, {
  code: 992,
  iso: "TJ",
  name: "Tajikistan",
  rate: 46
}, {
  code: 993,
  iso: "TM",
  name: "Turkmenistan",
  rate: 33
}, {
  code: 994,
  iso: "AZ",
  name: "Azerbaijan",
  rate: 42
}, {
  code: 995,
  iso: "GE",
  name: "Georgia",
  rate: 17
}, {
  code: 996,
  iso: "KG",
  name: "Kyrgyzstan",
  rate: 46
}, {
  code: 998,
  iso: "UZ",
  name: "Uzbekistan",
  rate: 46
}];

export const SmsCalculator = () => {
  const GSM7_BASIC = new Set(['@', '\u00a3', '$', '\u00a5', '\u00e8', '\u00e9', '\u00f9', '\u00ec', '\u00f2', '\u00c7', '\n', '\u00d8', '\u00f8', '\r', '\u00c5', '\u00e5', '\u0394', '_', '\u03a6', '\u0393', '\u039b', '\u03a9', '\u03a0', '\u03a8', '\u03a3', '\u0398', '\u039e', ' ', '\u00c6', '\u00e6', '\u00df', '\u00c9', ' ', '!', '"', '#', '\u00a4', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '\u00a1', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\u00c4', '\u00d6', '\u00d1', '\u00dc', '\u00a7', '\u00bf', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\u00e4', '\u00f6', '\u00f1', '\u00fc', '\u00e0']);
  const GSM7_EXT = new Set(['\f', '^', '{', '}', '\\', '[', '~', ']', '|', '\u20ac']);
  const flagUrl = iso => 'https://flagcdn.com/w40/' + iso.toLowerCase() + '.png';
  const calculate = (text, rate) => {
    let segments = 0;
    let isGsm7 = true;
    let units = 0;
    let limit = 160;
    if (text && text.length > 0) {
      let septets = 0;
      for (const ch of text) {
        if (GSM7_BASIC.has(ch)) septets += 1; else if (GSM7_EXT.has(ch)) septets += 2; else {
          isGsm7 = false;
          break;
        }
      }
      if (isGsm7) {
        units = septets;
        if (septets === 0) {
          segments = 0;
          limit = 160;
        } else if (septets <= 160) {
          segments = 1;
          limit = 160;
        } else {
          segments = Math.ceil(septets / 153);
          limit = 153;
        }
      } else {
        units = text.length;
        if (units <= 70) {
          segments = 1;
          limit = 70;
        } else {
          segments = Math.ceil(units / 67);
          limit = 67;
        }
      }
    }
    return {
      segments,
      total: segments * rate,
      isGsm7,
      units,
      limit
    };
  };
  const fmt = n => Number.isInteger(n) ? n.toString() : parseFloat(n.toFixed(4)).toString();
  const pluralize = (n, w) => n === 1 ? w : w + 's';
  const [selectedIso, setSelectedIso] = useState('US');
  const [text, setText] = useState('Hello! This is a test message to see how the segment calculation works.');
  const [open, setOpen] = useState(false);
  const [search, setSearch] = useState('');
  const dropdownRef = useRef(null);
  const searchInputRef = useRef(null);
  const sorted = useMemo(() => [...SMS_COUNTRIES].sort((a, b) => a.name.localeCompare(b.name)), []);
  const selectedCountry = useMemo(() => SMS_COUNTRIES.find(c => c.iso === selectedIso) || SMS_COUNTRIES[0], [selectedIso]);
  const selectedRate = selectedCountry.rate;
  const filtered = useMemo(() => {
    const q = search.toLowerCase();
    return sorted.filter(c => c.name.toLowerCase().includes(q) || c.iso.toLowerCase().includes(q) || ('+' + c.code).includes(search));
  }, [sorted, search]);
  const r = useMemo(() => calculate(text, selectedRate), [text, selectedRate]);
  useEffect(() => {
    if (open) {
      setSearch('');
      const t = setTimeout(() => {
        if (searchInputRef.current) searchInputRef.current.focus();
      }, 10);
      return () => clearTimeout(t);
    }
  }, [open]);
  useEffect(() => {
    const handleClickOutside = e => {
      if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
        setOpen(false);
      }
    };
    if (typeof document !== 'undefined') {
      document.addEventListener('click', handleClickOutside);
      return () => document.removeEventListener('click', handleClickOutside);
    }
  }, []);
  const selectCountry = c => {
    setSelectedIso(c.iso);
    setOpen(false);
  };
  const inSegPos = r.units === 0 ? 0 : (r.units - 1) % r.limit + 1;
  const remaining = r.limit - inSegPos;
  const pct = r.units === 0 ? 0 : Math.min(100, inSegPos / r.limit * 100);
  let progressClass = 'progress-fill';
  if (pct >= 100) progressClass += ' full'; else if (pct > 85) progressClass += ' warn';
  let segmentsMeta = 'No message yet';
  if (r.segments === 1) segmentsMeta = 'Single SMS'; else if (r.segments > 1) segmentsMeta = 'Concatenated SMS';
  let unitsMeta = 'of ' + r.limit + ' in this segment';
  if (r.units !== 0) unitsMeta = remaining + ' left in current segment';
  let encMeta;
  if (r.isGsm7) encMeta = r.segments > 1 ? '7-bit \u00b7 153 chars/segment' : '7-bit \u00b7 160 chars/segment'; else encMeta = r.segments > 1 ? '16-bit \u00b7 67 chars/segment' : '16-bit \u00b7 70 chars/segment';
  const CSS = '.sms-calc-root{--sms-bg:#fff;--sms-surface:#f7f7f7;--sms-ink:hsl(240 10% 3.9%);--sms-ink-soft:hsl(240 3.8% 46.1%);--sms-ink-mute:hsl(240 5% 64.9%);--sms-rule:hsl(240 5.9% 90%);--sms-rule-soft:hsl(240 4.8% 95.9%);--sms-ring:hsl(240 5.9% 10%);--sms-ring-soft:hsl(240 5.9% 10% / .18);--sms-muted:hsl(240 4.8% 95.9%);--sms-green:#15803d;--sms-green-soft:#dcfce7;--sms-amber:#b45309;--sms-amber-soft:#fef3c7;--sms-radius:10px;--sms-radius-card:14px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;color:var(--sms-ink)}' + '.dark .sms-calc-root,html.dark .sms-calc-root{--sms-bg:#1F1F1F;--sms-surface:rgba(255,255,255,.025);--sms-ink:#f3f4f6;--sms-ink-soft:#c8c8c8;--sms-rule:rgba(255,255,255,.08);--sms-rule-soft:rgba(255,255,255,.04);--sms-ring:hsl(240 4.9% 83.9%);--sms-ring-soft:hsl(240 4.9% 83.9% / .25);--sms-muted:rgba(255,255,255,.12);--sms-green:#22c55e;--sms-green-soft:#14532d;--sms-amber:#f59e0b;--sms-amber-soft:#451a03}' + '.sms-calc-root *,.sms-calc-root *::before,.sms-calc-root *::after{box-sizing:border-box}' + '.sms-calc-root img{margin:0}' + '.sms-calc-root .wrap{max-width:100%;padding:24px 0}' + '.sms-calc-root .hero-label{font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:var(--sms-ink-soft);margin-bottom:8px}' + '.sms-calc-root .hero-value{font-weight:700;font-size:48px;line-height:1;letter-spacing:-2px;display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;color:var(--sms-ink)}' + '.sms-calc-root .hero-unit{font-size:16px;font-weight:500;color:var(--sms-ink-soft);text-transform:lowercase;letter-spacing:normal}' + '.sms-calc-root .hero-breakdown{margin-top:16px;padding-top:12px;border-top:1px solid var(--sms-rule);font-size:12px;color:var(--sms-ink-soft)}' + '.sms-calc-root .hero-breakdown strong{color:var(--sms-ink);font-weight:600}' + '.sms-calc-root .sms-card{background:var(--sms-surface);border:1px solid var(--sms-rule);border-radius:var(--sms-radius-card);padding:20px;margin-bottom:16px}' + '.sms-calc-root .card-section + .card-section{margin-top:20px;padding-top:20px;border-top:1px solid var(--sms-rule)}' + '.sms-calc-root .field-label{font-size:13px;font-weight:500;color:var(--sms-ink);margin-bottom:8px;display:flex;justify-content:space-between;align-items:center}' + '.sms-calc-root .field-label .help{font-size:11px;font-weight:400;color:var(--sms-ink-mute)}' + '.sms-calc-root .dropdown{position:relative;width:100%}' + '.sms-calc-root .dropdown-selected{width:100%;height:36px;background:transparent;border:1px solid var(--sms-rule);border-radius:var(--sms-radius);padding:4px 12px;font-size:14px;color:var(--sms-ink);cursor:pointer;transition:border-color .15s,box-shadow .15s;display:flex;align-items:center;gap:10px;user-select:none}' + '.sms-calc-root .dropdown-selected.open{border-color:var(--sms-ring);box-shadow:0 0 0 3px var(--sms-ring-soft)}' + '.sms-calc-root .dropdown-selected .arrow{margin-left:auto;transition:transform .2s;color:var(--sms-ink)}' + '.sms-calc-root .dropdown-selected.open .arrow{transform:rotate(180deg)}' + '.sms-calc-root .dropdown-selected img{width:20px;height:14px;object-fit:cover;border-radius:2px}' + '.sms-calc-root .dropdown-list{position:absolute;top:calc(100% + 4px);left:0;right:0;background:var(--sms-bg);border:1px solid var(--sms-rule);border-radius:var(--sms-radius);box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.06);z-index:1000;display:flex;flex-direction:column;overflow:hidden}' + '.sms-calc-root .dropdown-search{background:var(--sms-bg);padding:0 12px;border-bottom:1px solid var(--sms-rule);display:flex;align-items:center;gap:8px;flex-shrink:0}' + '.sms-calc-root .dropdown-search-icon{width:16px;height:16px;color:var(--sms-ink-mute);flex-shrink:0}' + '.sms-calc-root .dropdown-search input{width:100%;height:44px;background:transparent;border:none;padding:0;font-size:14px;color:var(--sms-ink);outline:none}' + '.sms-calc-root .dropdown-search input::placeholder{color:var(--sms-ink-mute)}' + '.sms-calc-root .dropdown-options{padding:4px;max-height:236px;overflow-y:auto}' + '.sms-calc-root .dropdown-option{padding:6px 8px;display:flex;align-items:center;gap:10px;cursor:pointer;font-size:14px;border-radius:6px;color:var(--sms-ink)}' + '.sms-calc-root .dropdown-option:hover,.sms-calc-root .dropdown-option.selected{background:var(--sms-muted)}' + '.sms-calc-root .dropdown-option img{width:20px;height:14px;object-fit:cover;border-radius:2px;flex-shrink:0}' + '.sms-calc-root .dropdown-option .country-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' + '.sms-calc-root .dropdown-option .country-rate{font-size:11px;color:var(--sms-ink-soft);flex-shrink:0}' + '.sms-calc-root .dropdown-option .check-icon{width:16px;height:16px;color:var(--sms-ink);flex-shrink:0;opacity:0;margin-left:4px}' + '.sms-calc-root .dropdown-option.selected .check-icon{opacity:1}' + '.sms-calc-root .dropdown-empty{padding:24px 12px;text-align:center;font-size:13px;color:var(--sms-ink-soft)}' + '.sms-calc-root textarea{width:100%;background:transparent;border:1px solid var(--sms-rule);border-radius:var(--sms-radius);padding:8px 12px;font-family:inherit;font-size:14px;line-height:1.5;color:var(--sms-ink);resize:vertical;min-height:100px;outline:none;transition:border-color .15s,box-shadow .15s}' + '.sms-calc-root textarea:focus{border-color:var(--sms-ring);box-shadow:0 0 0 3px var(--sms-ring-soft)}' + '.sms-calc-root textarea::placeholder{color:var(--sms-ink-mute)}' + '.sms-calc-root .progress-row{margin-top:10px;display:flex;align-items:center;gap:12px}' + '.sms-calc-root .progress-track{flex:1;height:4px;background:var(--sms-rule-soft);border-radius:999px;overflow:hidden}' + '.sms-calc-root .progress-fill{height:100%;background:var(--sms-ink);border-radius:999px;transition:width .25s ease,background .2s}' + '.sms-calc-root .progress-fill.warn{background:var(--sms-amber)}' + '.sms-calc-root .progress-fill.full{background:var(--sms-green)}' + '.sms-calc-root .progress-text{font-size:11px;color:var(--sms-ink-soft);white-space:nowrap}' + '.sms-calc-root .stats{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}' + '@media (max-width:540px){.sms-calc-root .stats{grid-template-columns:1fr}.sms-calc-root .hero-value{font-size:36px}}' + '.sms-calc-root .stat-label{font-size:11px;color:var(--sms-ink-soft);margin-bottom:4px;font-weight:500;text-transform:uppercase;letter-spacing:.5px}' + '.sms-calc-root .stat-value{font-weight:700;font-size:22px;line-height:1.2;letter-spacing:-.5px;color:var(--sms-ink)}' + '.sms-calc-root .stat-meta{font-size:10px;color:var(--sms-ink-mute);margin-top:2px}' + '.sms-calc-root .sms-badge{display:inline-flex;align-items:center;gap:5px;padding:3px 8px;border-radius:999px;font-size:11px;font-weight:600;letter-spacing:.3px}' + '.sms-calc-root .sms-badge.gsm{background:var(--sms-green-soft);color:var(--sms-green)}' + '.sms-calc-root .sms-badge.ucs{background:var(--sms-amber-soft);color:var(--sms-amber)}' + '.sms-calc-root .sms-badge::before{content:"";width:5px;height:5px;border-radius:999px;background:currentColor}' + '.sms-calc-root .rate-display{margin-top:12px;font-size:12px;color:var(--sms-ink-soft);display:inline-flex;align-items:center;gap:6px;background:var(--sms-muted);border:1px solid var(--sms-rule);border-radius:8px;padding:2px 8px}' + '.sms-calc-root .rate-display strong{color:var(--sms-ink);font-weight:600;font-size:13px}';
  return <div className="sms-calc-root">
      <style dangerouslySetInnerHTML={{
    __html: CSS
  }} />
      <div className="wrap">
        <div className="sms-card">
          <div className="card-section">
            <div className="field-label">
              <span>Destination country</span>
              <span className="help">select recipient's country</span>
            </div>
            <div className="dropdown" ref={dropdownRef}>
              <div className={'dropdown-selected' + (open ? ' open' : '')} onClick={() => setOpen(v => !v)}>
                <img src={flagUrl(selectedCountry.iso)} alt={selectedCountry.iso} />
                <span>{selectedCountry.name} (+{selectedCountry.code})</span>
                <svg className="arrow" width="12" height="12" viewBox="0 0 12 12">
                  <path fill="currentColor" d="M6 8L1 3h10z" />
                </svg>
              </div>
              {open && <div className="dropdown-list">
                  <div className="dropdown-search">
                    <svg className="dropdown-search-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                      <circle cx="11" cy="11" r="8" />
                      <path d="m21 21-4.3-4.3" />
                    </svg>
                    <input ref={searchInputRef} type="text" placeholder="Search country..." value={search} onChange={e => setSearch(e.target.value)} />
                  </div>
                  <div className="dropdown-options">
                    {filtered.length === 0 ? <div className="dropdown-empty">No results found.</div> : filtered.map(c => <div key={c.iso} className={'dropdown-option' + (c.iso === selectedIso ? ' selected' : '')} onClick={() => selectCountry(c)}>
                          <img src={flagUrl(c.iso)} alt={c.iso} />
                          <span className="country-name">{c.name} (+{c.code})</span>
                          <span className="country-rate">{c.rate} cr/seg</span>
                          <svg className="check-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                            <polyline points="20 6 9 17 4 12" />
                          </svg>
                        </div>)}
                  </div>
                </div>}
            </div>
            <div className="rate-display">
              Rate: <strong>{selectedRate}</strong> credit(s) per segment
            </div>
          </div>

          <div className="card-section">
            <div className="field-label">
              <span>Message text</span>
              <span className="help">
                {text.length} {pluralize(text.length, 'character')}
              </span>
            </div>
            <textarea value={text} onChange={e => setText(e.target.value)} placeholder="Type your SMS message here to calculate the cost..." />
            <div className="progress-row">
              <div className="progress-track">
                <div className={progressClass} style={{
    width: pct + '%'
  }} />
              </div>
              <span className="progress-text">
                {r.units} / {r.limit}
              </span>
            </div>
          </div>
        </div>

        <div className="sms-card">
          <div className="card-section">
            <div className="hero">
              <div className="hero-label">Total Cost</div>
              <div className="hero-value">
                <span>{fmt(r.total)}</span>
                <span className="hero-unit">credits</span>
              </div>
              <div className="hero-breakdown">
                <strong>{r.segments}</strong> {pluralize(r.segments, 'segment')} {'\u00d7'}{' '}
                <strong>{fmt(selectedRate)}</strong> {pluralize(selectedRate, 'credit')} each
              </div>
            </div>
          </div>

          <div className="card-section">
            <div className="stats">
              <div className="stat">
                <div className="stat-label">Segments</div>
                <div className="stat-value">{r.segments}</div>
                <div className="stat-meta">{segmentsMeta}</div>
              </div>
              <div className="stat">
                <div className="stat-label">Encoding</div>
                <div className="stat-value" style={{
    marginTop: '2px'
  }}>
                  <span className={'sms-badge ' + (r.isGsm7 ? 'gsm' : 'ucs')}>
                    {r.isGsm7 ? 'GSM-7' : 'UCS-2'}
                  </span>
                </div>
                <div className="stat-meta">{encMeta}</div>
              </div>
              <div className="stat">
                <div className="stat-label">Characters used</div>
                <div className="stat-value">{r.units}</div>
                <div className="stat-meta">{unitsMeta}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>;
};

<Callout icon="phone" color="#2563EB" iconType="regular">Available for **Pearl Voice** only.</Callout>

<div className="block dark:hidden">
  <Frame>
    <div className="p-1">
      <img src="https://mintcdn.com/nlpearl/BSZMdFdUnvFjMIlB/images/dark_mode/sendsmsactioncov.svg?fit=max&auto=format&n=BSZMdFdUnvFjMIlB&q=85&s=38618d9bb17d24d466eccff285169874" alt="Send Email action interface on light mode" className="rounded-[14px]" width="1048" height="720" data-path="images/dark_mode/sendsmsactioncov.svg" />
    </div>
  </Frame>
</div>

<div className="hidden dark:block">
  <Frame>
    <div className="p-1">
      <img src="https://mintcdn.com/nlpearl/BSZMdFdUnvFjMIlB/images/dark_mode/sendsmsactioncov.svg?fit=max&auto=format&n=BSZMdFdUnvFjMIlB&q=85&s=38618d9bb17d24d466eccff285169874" alt="Send Email action interface on dark mode" className="rounded-[14px]" width="1048" height="720" data-path="images/dark_mode/sendsmsactioncov.svg" />
    </div>
  </Frame>
</div>

The **Send SMS** node lets your AI agent send an SMS in real time, during the conversation (In-Call) or after it ends (Post-Call), so your customers receive important information instantly.

***

## Adding the Node

In the Flow Editor, add a **Send SMS** node where you want the message to be sent.

| Context       | Where to add it                                                                |
| ------------- | ------------------------------------------------------------------------------ |
| **In-Call**   | Place the node in the conversation, at the point where the SMS should be sent. |
| **Post-Call** | Add it as a **Post-Call action** to send the SMS once the call ends.           |

<Note>
  The SMS is sent based on where the node sits in your flow, there is **no separate trigger field** on the node itself.
</Note>

***

## Fields to Configure

<Frame>
  <img src="https://mintcdn.com/nlpearl/WcOkMoSGTOGYk4-M/images/dark_mode/senssmsimage.png?fit=max&auto=format&n=WcOkMoSGTOGYk4-M&q=85&s=9476e376f58f427f676f591818b0cefd" alt="Send SMS node configuration with To and SMS Content fields" className="rounded-[14px]" width="5120" height="2880" data-path="images/dark_mode/senssmsimage.png" />
</Frame>

<Steps>
  <Step title="To">
    The recipient phone number(s), entered as tags. **At least one recipient is required**, and you can mix both modes below in the same field.

    **Send to the customer (dynamic)** — Insert the built-in **phone number** variable with the variable picker. At send time it resolves to the number of the person on the call, including the country code (e.g. `+1 234 567 8900`), and is stored as `{phoneNumber}`. This is the most common setup: the SMS goes to the customer you're talking to.

    **Send to a fixed number (static)** — Type a number and press **Space** or **Enter** to turn it into a tag. Use this to always notify the same destination (an internal team, a manager, a back-office line), whoever is on the call.

    <Info>
      Only the built-in **phone number** variable can be inserted here. Custom variables (including numbers collected during the call) are **not** available in the To field, only static numbers or the customer's phone number. This mirrors the Email node's **To** field, which only accepts the **email address** variable.
    </Info>

    **Accepted format**: an optional leading `+` followed by 1 to 20 digits, with no spaces, dashes, or parentheses. Invalid entries are rejected and not added as a tag.

    | Valid          | Invalid           |
    | -------------- | ----------------- |
    | `+15551234567` | `+1 555 123 4567` |
    | `0612345678`   | `(555) 123-4567`  |
  </Step>

  <Step title="SMS Content">
    Write the message to send. You can include links and details, and insert variables to personalize it, for example: `Hi {firstName}, your reservation at {restaurantName} is confirmed.`

    Available variables depend on where the node runs:

    | Context       | Available variables                                     |
    | ------------- | ------------------------------------------------------- |
    | **In-Call**   | Pre-Call + In-Call                                      |
    | **Post-Call** | Pre-Call + In-Call + Post-Call (e.g. summary, duration) |
  </Step>
</Steps>

<Info>
  **Regulatory compliance** — To stay compliant, Pearl always asks the customer for consent before sending an SMS, respecting their preferences and communication laws.
</Info>

***

## Example Use Cases

<CardGroup cols={2}>
  <Card title="Reservation confirmations" icon="calendar-check" iconType="light">
    After confirming a reservation, Pearl automatically sends an SMS with the details.
  </Card>

  <Card title="Appointment reminders" icon="bell" iconType="light">
    Pearl sends a reminder SMS about an upcoming appointment or event.
  </Card>
</CardGroup>

***

## SMS Credit Cost

<Info>
  Sending an SMS consumes credits from your account balance. The cost depends on:

  * **Recipient country**: each destination has its own rate per segment.
  * **Number of segments**: longer messages are split into multiple segments, each billed individually.
</Info>

A standard segment holds up to **160 characters** (GSM-7). With special characters or emojis, encoding switches to UCS-2 and the limit drops to **70 characters** per segment. Messages exceeding one segment are concatenated, with each segment charged separately.

| Encoding               | Single SMS limit | Concatenated segment limit |
| ---------------------- | ---------------- | -------------------------- |
| GSM-7 (standard)       | 160 characters   | 153 characters per segment |
| UCS-2 (unicode/emojis) | 70 characters    | 67 characters per segment  |

<Warning>
  If your SMS contains **variables** (e.g. `firstName`), the final cost may vary, since the number of characters, and therefore segments, depends on each variable's value at send time.
</Warning>

### SMS Credit Calculator

Use this calculator to estimate how many segments your message will use and the total credit cost based on the destination country.

<SmsCalculator />
