uNoti SMS Providers: Bangladesh - MunifTanjim/unoti GitHub Wiki

uNoti SMS Providers: Bangladesh

Helpers:

const nonAsciiRegex = /[^\u0000-\u007F]/

export function includesNonAsciiCharacter(string: string): boolean {
  return nonAsciiRegex.test(string)
}

export type SMSParams = {
  to: string
  text: string
}

AjuraTech

Homepage: https://www.ajuratech.com
Dashboard: http://sms.ajuratech.com/Account/Login

import fetch from 'node-fetch'
import qs from 'qs'
import type { NotiProvider } from 'unoti'

type AjuraTechResponse = {
  ErrorCode:
    | '000'
    | '001'
    | '003'
    | '004'
    | '005'
    | '006'
    | '007'
    | '008'
    | '009'
    | '010'
    | '011'
    | '012'
    | '013'
    | '014'
    | '015'
    | '017'
    | '018'
    | '019'
    | '020'
    | '021'
    | '022'
    | '023'
    | '024'
    | '025'
    | '026'
    | '027'
  ErrorMessage:
    | 'Done'
    | 'login details cannot be blank'
    | 'sender cannot be blank'
    | 'message text cannot be blank'
    | 'message data cannot be blank'
    | 'error: generic error description'
    | 'username or password is invalid'
    | 'account not active'
    | 'account locked, contact your account manager'
    | 'api restriction'
    | 'ip address restriction'
    | 'invalid length of message text'
    | 'mobile numbers not valid'
    | 'account locked due to spam message contact support'
    | 'senderid not valid'
    | 'groupid not valid'
    | 'multi message to group is not supported'
    | 'schedule date is not valid'
    | 'message or mobile number cannot be blank'
    | 'insufficient credits'
    | 'invalid jobid'
    | 'parameter missing'
    | 'invalid template or template mismatch'
    | '{Field} can not be blank or empty'
    | 'invalid date range'
    | 'invalid optin user'
    | string
  JobId: string
  MessageData: Array<{
    Number: string
    MessageId: string
  }>
}

type AjuraTechAuthParams =
  | { user: string; password: string }
  | { APIKey: string }

type AjuraTechQueryParams = AjuraTechAuthParams & {
  senderid: string
  channel: 'Normal' | string
  DCS: 0 | 8
  flashsms: 0 | 1
  number: string
  text: string
  schedtime?: string
  groupid?: string
}

const nonAsciiRegex = /[^\u0000-\u007F]/

function includesNonAsciiCharacter(string: string): boolean {
  return nonAsciiRegex.test(string)
}

export const getAjuratechSMSProvider = ({
  id = 'ajuratech',
  apiUrl = 'http://sms.ajuratech.com/api/mt/SendSMS',
  user,
  password,
  from,
}: {
  id?: string
  apiUrl?: string
  user: string
  password: string
  from: string
}): NotiProvider<SMSParams> => {
  const ajuratechSMSProvider: NotiProvider<SMSParams> = {
    id,
    send: async (request) => {
      const { to, text } = request

      const hasNonAsciiText = includesNonAsciiCharacter(text)

      const queryParams: AjuraTechQueryParams = {
        user,
        password,
        senderid: from,
        channel: 'Normal',
        DCS: hasNonAsciiText ? 8 : 0,
        flashsms: 0,
        number: to,
        text,
      }

      const response = await fetch(`${apiUrl}?${qs.stringify(queryParams)}`)

      const data: AjuraTechResponse = await response.json()

      if (data.ErrorCode !== '000') {
        throw new Error(
          `AjuraTech SMS Failure: ${JSON.stringify({
            ErrorCode: data.ErrorCode,
            ErrorMessage: data.ErrorMessage,
          })}`
        )
      }

      const id = data.MessageData.length ? data.MessageData[0].MessageId : ''

      return {
        id,
      }
    },
  }

  return ajuratechSMSProvider
}

MobiReach

Dashboard: https://user.mobireach.com.bd

import camaro from 'camaro'
import fetch from 'node-fetch'
import qs from 'qs'
import type { NotiProvider } from 'unoti'

type MobiReachResponse = {
  ArrayOfServiceClass: {
    ServiceClass: {
      MessageId: '0' | string
      Status: '-1' | string
      StatusText: 'Error occurred' | 'success' | string
      ErrorCode: '1504' | '1505' | string
      ErrorText:
        | 'auth_fail'
        | 'dest_address_missing'
        | 'source_address_missing'
        | 'username_missing'
        | string
      SMSCount: '0' | '1' | string
      CurrentCredit: '0' | string
    }
  }
}

const mobireachResponseTemplate: MobiReachResponse = {
  ArrayOfServiceClass: {
    ServiceClass: {
      MessageId: '/ArrayOfServiceClass/ServiceClass/MessageId',
      Status: '/ArrayOfServiceClass/ServiceClass/Status',
      StatusText: '/ArrayOfServiceClass/ServiceClass/StatusText',
      ErrorCode: '/ArrayOfServiceClass/ServiceClass/ErrorCode',
      ErrorText: '/ArrayOfServiceClass/ServiceClass/ErrorText',
      SMSCount: '/ArrayOfServiceClass/ServiceClass/SMSCount',
      CurrentCredit: '/ArrayOfServiceClass/ServiceClass/CurrentCredit',
    },
  },
}

export const getMobireachSMSProvider = ({
  id = 'mobireach',
  apiUrl = 'https://api.mobireach.com.bd/SendTextMessage',
  user,
  password,
  from,
}: {
  id?: string
  apiUrl?: string
  user: string
  password: string
  from: string
}): NotiProvider<SMSParams> => {
  const mobireachSMSProvider: NotiProvider<SMSParams> = {
    id,
    send: async (request) => {
      const { to, text } = request

      const queryParams = {
        Username: user,
        Password: password,
        From: from,
        To: to,
        Message: text,
        submit: 'submit',
      }

      const response = await fetch(`${apiUrl}?${qs.stringify(queryParams)}`)

      const xmlString = await response.text()

      const { ArrayOfServiceClass }: MobiReachResponse = await camaro.transform(
        xmlString,
        mobireachResponseTemplate
      )

      if (ArrayOfServiceClass.ServiceClass.StatusText !== 'success') {
        throw new Error(
          `MobiReach SMS Failure: ${JSON.stringify(
            ArrayOfServiceClass.ServiceClass
          )}`
        )
      }

      const id = ArrayOfServiceClass.ServiceClass.MessageId

      return {
        id,
      }
    },
  }

  return mobireachSMSProvider
}

SSLWireless

Dashboard: https://isms.sslwireless.com

import camaro from 'camaro'
import fetch from 'node-fetch'
import qs from 'qs'
import type { NotiProvider } from 'unoti'

type SSLWirelessResponse = {
  REPLY: {
    PARAMETER: 'OK' | 'All PARAMETERS ARE NOT EXISTS' | string
    LOGIN: 'SUCCESSFULL' | 'FAIL' | string
    PUSHAPI: 'ACTIVE' | string
    STAKEHOLDERID: 'OK' | string
    PERMITTED: 'OK' | string
    SMSINFO: {
      MSISDN: string
      SMSTEXT: string
      CSMSID: string
      REFERENCEID: string
      SMSVALUE: 'SMS or Mobile is empty' | string
    }
  }
}

const sslWirelessResponseTemplate: SSLWirelessResponse = {
  REPLY: {
    PARAMETER: '/REPLY/PARAMETER',
    LOGIN: '/REPLY/LOGIN',
    PUSHAPI: '/REPLY/PUSHAPI',
    STAKEHOLDERID: '/REPLY/STAKEHOLDERID',
    PERMITTED: '/REPLY/PERMITTED',
    SMSINFO: {
      MSISDN: '/REPLY/SMSINFO/MSISDN',
      SMSTEXT: '/REPLY/SMSINFO/SMSTEXT',
      CSMSID: '/REPLY/SMSINFO/CSMSID',
      REFERENCEID: '/REPLY/SMSINFO/REFERENCEID',
      SMSVALUE: '/REPLY/SMSINFO/SMSVALUE',
    },
  },
}

const method = 'POST'
const headers = {
  'content-type': 'application/x-www-form-urlencoded',
}

export const getSslWirelessSMSProvider = ({
  id = 'sslwireless',
  apiUrl = 'https://sms.sslwireless.com/pushapi/dynamic/server.php',
  user,
  password,
  from,
}: {
  id?: string
  apiUrl?: string
  user: string
  password: string
  from: string
}): NotiProvider<SMSParams> => {
  const sslWirelessSMSProvider: NotiProvider<SMSParams> = {
    id,
    send: async (params) => {
      const { to, text } = params

      const hasNonAsciiText = includesNonAsciiCharacter(text)

      if (hasNonAsciiText) {
        throw new Error(
          `SSLWireless SMS Failure: non-ascii characters not supported!`
        )
      }

      const body = qs.stringify({
        user,
        pass: password,
        sid: from,
        'sms[0][0]': to,
        'sms[0][1]': text,
        'sms[0][2]': Math.floor(Date.now() / 1000),
      })

      const response = await fetch(apiUrl, { method, headers, body })

      const xmlString = await response.text()

      const { REPLY }: SSLWirelessResponse = await camaro.transform(
        xmlString,
        sslWirelessResponseTemplate
      )

      if (REPLY.PERMITTED !== 'OK') {
        throw new Error(`SSLWireless SMS Failure: ${JSON.stringify(REPLY)}`)
      }

      const id = REPLY.SMSINFO.REFERENCEID

      return {
        id,
      }
    },
  }

  return sslWirelessSMSProvider
}

SMSPlusSSLWireless

Dashboard: https://ismsplus.sslwireless.com

import fetch from 'node-fetch'
import type { NotiProvider } from 'unoti'

type SMSPlusSSLWirelessResponse = {
  status: 'SUCCESS' | 'FAILED'
  status_code: 200 | 4001 | 4002 | 4022 | 4025 | number
  error_message:
    | ''
    | 'Unauthorized'
    | 'SID/Stakeholder is not permitted'
    | 'The api token field is required.'
    | 'Invalid MSISDN'
    | string
  smsinfo: Array<{
    sms_status: 'INVALID' | 'SUCCESS' | 'FAILED'
    status_message: 'Success' | 'Invalid MSISDN' | string
    msisdn: string
    sms_type: 'EN' | string
    sms_body: string
    csms_id: string
    reference_id: string
  }>
}

const method = 'POST'
const headers = {
  'content-type': 'application/json',
}

export const getSmsPlusSslWirelessSMSProvider = ({
  id = 'smsplus-sslwireless',
  apiUrl = 'https://smsplus.sslwireless.com/api/v3/send-sms',
  apiToken,
  from,
}: {
  id?: string
  apiUrl?: string
  apiToken: string
  from: string
}): NotiProvider<SMSParams> => {
  const smsPlusSslWirelessSMSProvider: NotiProvider<SMSParams> = {
    id,
    send: async (params) => {
      const { to, text } = params

      const body = JSON.stringify({
        api_token: apiToken,
        sid: from,
        msisdn: to,
        sms: text,
        csms_id: '123456',
      })

      const response = await fetch(apiUrl, { method, body, headers })

      const data: SMSPlusSSLWirelessResponse = await response.json()

      if (data.status_code !== 200) {
        throw new Error(
          `SMSPlusSSLWireless SMS Failure: ${JSON.stringify(data)}`
        )
      }

      const id =
        data.smsinfo && data.smsinfo.length
          ? data.smsinfo.map((info) => info.reference_id).join(',')
          : String(Date.now())

      return {
        id,
      }
    },
  }

  return smsPlusSslWirelessSMSProvider
}
⚠️ **GitHub.com Fallback** ⚠️