+## Table Of Contents
+
+
+
+
+- [Why?](#why)
+- [Web UI](#web-ui)
+- [API](#api)
+- [Android App](#android-app)
+- [Chat/forum](#chatforum)
+- [Features](#features)
+ - [End-to-end Encryption](#end-to-end-encryption)
+ - [Webhook](#webhook)
+ - [Back Pressure](#back-pressure)
+ - [Message Expiration](#message-expiration)
+- [API Clients](#api-clients)
+- [Flows](#flows)
+ - [Sending an SMS Message](#sending-an-sms-message)
+- [Self Host Setup - Docker](#self-host-setup---docker)
+ - [1. Setup Firebase](#1-setup-firebase)
+ - [2. Setup SMTP Email service](#2-setup-smtp-email-service)
+ - [3. Setup Cloudflare Turnstile](#3-setup-cloudflare-turnstile)
+ - [4. Download the code](#4-download-the-code)
+ - [5. Setup the environment variables](#5-setup-the-environment-variables)
+ - [6. Build and Run](#6-build-and-run)
+ - [7. Create the System User](#7-create-the-system-user)
+ - [8. Build the Android App.](#8-build-the-android-app)
+- [Integration Testing](#integration-testing)
+- [License](#license)
+
+
+
## Why?
I'm originally from Cameroon and I wanted an automated way to send and receive SMS messages using an API.
Unfortunately many countries don't support the ability to buy virtual phone numbers, and I could not find a good ready-made
solution that could help me send/receive SMS messages using a mobile phone using an intuitive http API.
-## Technology
-
-### Web
+## Web UI
The web interface https://httpsms.com is built using [Nuxt](https://nuxtjs.org/) and [Vuetify](https://vuetifyjs.com/en/).
It is hosted as a single page application on firebase. The source code is in the [web](./web) directory
-### API
+## API
The API https://api.httpsms.com is built using [Fiber](https://gofiber.io/), Go and [CockroachDB](https://www.cockroachlabs.com/) for the database.
-It rus as a serverless application on Google Cloud Run. The API documentation can be found here https://api.httpsms.com/index.html
+It runs as a serverless application on Google Cloud Run. The API documentation can be found here https://api.httpsms.com/index.html
```go
// Sending an SMS Message using Go
@@ -40,14 +77,29 @@ client.Messages.Send(context.Background(), &httpsms.MessageSendParams{
})
```
-### Android App
+## Android App
+
+[The Android App](https://apk.httpsms.com/HttpSms.apk) is a native application built using Kotlin with material design principles.
+This app must be installed on an Android phone before you can start sending and receiving SMS messages.
+
+[
](https://github.com/NdoleStudio/httpsms/releases/)
+
+## Chat/forum
-[The Android App](https://github.com/NdoleStudio/httpsms/releases/download/v0.0.1/HttpSms.apk) is a native application
-built using Kotlin with material design principles. This app must be installed on an android phone before you can start
-sending and receiving SMS messages.
+There are a few ways to get in touch with me and/or the rest of the community. Feel free to use any of these methods. Whatever
+works best for you:
+
+- [Discord server](https://discord.gg/kGk8HVqeEZ) - direct chat with the community
+- [GitHub issues](https://github.com/NdoleStudio/httpsms/issues) - questions, features, bugs
## Features
+### End-to-end Encryption
+
+You can encrypt your messages end-to-end using the military grade [AES-256 encryption](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)
+algorithm. Your encryption key is stored only on our mobile phone so the even the server won't have any way to view the
+content of your SMS messages which are sent and received on your Android phone.
+
### Webhook
If you want to build advanced integrations, we support webhooks. The httpSMS platform can forward SMS messages received
@@ -66,7 +118,8 @@ will be notified.
## API Clients
-- Go: https://github.com/NdoleStudio/httpsms-go
+- [x] Go: https://github.com/NdoleStudio/httpsms-go
+- [x] JavaScript/TypeScript: https://github.com/NdoleStudio/httpsms-node
## Flows
@@ -74,17 +127,157 @@ will be notified.
```mermaid
sequenceDiagram
-User->>+Http Sms API: Call /v1/messages/send API
-Http Sms API-->>+Google Cloud Task: Schedule notification about new message
-Http Sms API-->>-User: Respond with 202 (Accepted)
-Google Cloud Task-->>+Http Sms API: [Async] Send notfication request
-Http Sms API-->>-Android App: Send push notification about new message
-Android App-->>Http Sms API: [Async] Fetch message
-Android App-->>Android App: Send Message using Andoid SMS API
-Android App-->>Http Sms API: [Async] Send result of sending SMS
-Android App-->>Http Sms API: [Async] Send Delivery Report
+User->>+httpSMS API: Call /v1/messages/send API
+httpSMS API-->>+Push Queue: Schedule notification about new message
+httpSMS API-->>-User: Respond with 202 (Accepted)
+Push Queue-->>+httpSMS API: [Async] Send notification request
+httpSMS API-->>-Android App: Send push notification about new message
+Android App-->>httpSMS API: [Async] Fetch message
+Android App-->>Android App: Send Message using Android SMS API
+Android App-->>httpSMS API: [Async] Send result of sending SMS
+Android App-->>httpSMS API: [Async] Send Delivery Report
+```
+
+## Self Host Setup - Docker
+
+### 1. Setup Firebase
+
+- The httpSMS application uses [firebase cloud messaging](https://firebase.google.com/docs/cloud-messaging) for sending push notifications to your Android phone to trigger an SMS message to be sent out.
+ Visit the [firebase console](https://console.firebase.google.com/) and create a new project and follow the [steps here](https://firebase.google.com/docs/web/setup#register-app) to get your firebase web SDK config credentials.
+ For example, I created a firebase project called `httpsms-docker` and this is my web SDK configuration
+
+```js
+const firebaseConfig = {
+ apiKey: "AIzaSyAKqPvj51igvvNNcRtxxxxx",
+ authDomain: "httpsms-docker.firebaseapp.com",
+ projectId: "httpsms-docker",
+ storageBucket: "httpsms-docker.appspot.com",
+ messagingSenderId: "668063041624",
+ appId: "1:668063041624:web:29b9e3b702796xxxx",
+ measurementId: "G-18VRYL2xxxx",
+};
```
+- Enable `Email/Password` sign-in in the [Firebase console](https://console.firebase.google.com/u/0/), open the **Authentication** section. On the Sign in method tab, enable the `Email/password` sign-in method and click `Save`.
+ - The firebase `email/password` sign-in method has [a bug](https://github.com/firebase/firebaseui-web/issues/1040) which prevents you from signing in. The work around right now is to [disable email enumeration protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection#disable) on the firebase console.
+- Generate your firebase service account credentials by following the [steps here](https://firebase.google.com/docs/admin/setup#initialize_the_sdk_in_non-google_environments) and save the credentials in a file called `firebase-credentials.json` we will use this file to authenticate with the firebase admin SDK.
+- Generate your Android `google-services.json` file using [the instructions here](https://support.google.com/firebase/answer/7015592?hl=en#android&zippy=%2Cin-this-article) we will use it letter to configure the android app.
+
+### 2. Setup SMTP Email service
+
+The httpSMS application uses [SMTP](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol) to send emails to users e.g. when your Android phone has been offline for a long period of time.
+You can use a service like [mailtrap](https://mailtrap.io/) to create an SMTP server for development purposes.
+
+### 3. Setup Cloudflare Turnstile
+
+The message search route (`/v1/messages/search`) is protected by a [Cloudflare Turnstile](https://developers.cloudflare.com/turnstile/get-started/) captcha to prevent abuse. You need to set up a Turnstile widget for the search messages feature to work.
+
+1. Go to the [Cloudflare dashboard](https://dash.cloudflare.com/) and navigate to **Turnstile**.
+2. Add a new site and configure it for your self-hosted domain (e.g., `localhost` for local development).
+3. Note down the **Site Key** and **Secret Key** — you will need them for the frontend and backend environment variables respectively.
+
+### 4. Download the code
+
+Clone the httpSMS GitHub repository
+
+```bash
+git clone https://github.com/NdoleStudio/httpsms.git
+```
+
+### 5. Setup the environment variables
+
+- Copy the `.env.docker` file in the `web` directory into `.env`
+
+```bash
+cp web/.env.docker web/.env
+```
+
+- Update the environment variables in the `.env` file in the `web` directory with your firebase web SDK configuration in step 1 above
+
+```dotenv
+FIREBASE_API_KEY=
+FIREBASE_AUTH_DOMAIN=
+FIREBASE_PROJECT_ID=
+FIREBASE_STORAGE_BUCKET=
+FIREBASE_MESSAGING_SENDER_ID=
+FIREBASE_APP_ID=
+FIREBASE_MEASUREMENT_ID=
+
+# Cloudflare Turnstile site key from step 3
+CLOUDFLARE_TURNSTILE_SITE_KEY=
+```
+
+- Copy the `.env.docker` file in the `api` directory into `.env`
+
+```bash
+cp api/.env.docker api/.env
+```
+
+- Update the environment variables in the `.env` file in the `api` directory with your firebase service account credentials, SMTP server details, and Cloudflare Turnstile secret key.
+
+```dotenv
+# SMTP email server settings
+SMTP_USERNAME=
+SMTP_PASSWORD=
+SMTP_HOST=
+SMTP_PORT=
+
+# Firebase service account credentials
+FIREBASE_CREDENTIALS=
+
+# This is the `projectId` from your firebase web config
+GCP_PROJECT_ID=
+
+# Cloudflare Turnstile secret key from step 3
+CLOUDFLARE_TURNSTILE_SECRET_KEY=
+```
+
+- Don't bother about the `EVENTS_QUEUE_USER_API_KEY` and `EVENTS_QUEUE_USER_ID` settings. We will set that up later.
+
+### 6. Build and Run
+
+- Build and run the API, the web UI, database and cache using the `docker-compose.yml` file. It takes a while for build and download all the docker images.
+ When it's finished, you'll be able to access the web UI at http://localhost:3000 and the API at http://localhost:8000
+
+```bash
+docker compose up --build
+```
+
+### 7. Create the System User
+
+- The application uses the concept of a system user to process events asynchronously. You should manually create this user in `users` table in your database. Make sure you use the same `id` and `api_key` as the `EVENTS_QUEUE_USER_ID`, and `EVENTS_QUEUE_USER_API_KEY` in your `.env` file.
+
+ ```SQL
+ INSERT INTO users (id, api_key, email ) VALUES ('your-system-user-id', 'your-system-api-key', 'system@domain.com');
+ ```
+
+> [!IMPORTANT]
+> Restart your API docker container after modifying `EVENTS_QUEUE_USER_ID`, and `EVENTS_QUEUE_USER_API_KEY` in your `.env` file so that the httpSMS API can pick up the changes.
+
+### 8. Build the Android App.
+
+- Before building the Android app in [Android Studio](https://developer.android.com/studio), you need to replace the `google-services.json` file in the `android/app` directory with the file which you got from step 1. You need to do this for the firebase FCM messages to work properly.
+
+## Integration Testing
+
+The project includes end-to-end integration tests that validate the complete SMS send/receive lifecycle. Tests run the full stack (API, PostgreSQL, Redis) in Docker alongside a phone emulator that simulates an Android device.
+
+📖 **Full documentation:** [`tests/README.md`](tests/README.md)
+
+**Quick run:**
+
+```bash
+cd tests
+bash generate-firebase-credentials.sh
+export FIREBASE_CREDENTIALS=$(jq -c . firebase-credentials.json)
+docker compose up -d --build --wait
+docker compose wait seed && sleep 2
+go test -v -timeout 120s ./...
+docker compose down -v
+```
+
+Integration tests also run automatically in CI on every push/PR to `main`.
+
## License
This project is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 - see the [LICENSE](LICENSE) file for details
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..35c692f8c
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,13 @@
+# Security Policy
+
+## Supported Versions
+
+As of today, I only support the latest version of httpSMS in the `main` branch of github. Please make sure you stay up-to-date.
+
+| Version | Supported |
+| ------- | ------------------ |
+| main | :white_check_mark: |
+
+## Reporting a Vulnerability
+
+Please report severe security issues privately via arnold@httpsms.com or by sending me a private message on [Discord](https://discord.gg/kGk8HVqeEZ).
diff --git a/android/.gitignore b/android/.gitignore
index aa724b770..6c13541ca 100644
--- a/android/.gitignore
+++ b/android/.gitignore
@@ -12,4 +12,5 @@
/captures
.externalNativeBuild
.cxx
+.kotlin/sessions/
local.properties
diff --git a/android/app/build.gradle b/android/app/build.gradle
deleted file mode 100644
index 072771bb1..000000000
--- a/android/app/build.gradle
+++ /dev/null
@@ -1,67 +0,0 @@
-plugins {
- id 'com.android.application'
- id 'org.jetbrains.kotlin.android'
- id 'com.google.gms.google-services'
- id "io.sentry.android.gradle" version "3.1.2"
-}
-
-def getGitHash = { ->
- def stdout = new ByteArrayOutputStream()
- exec {
- commandLine 'git', 'rev-parse', '--short', 'HEAD'
- standardOutput = stdout
- }
- return stdout.toString().trim()
-}
-
-android {
- compileSdk 33
-
- defaultConfig {
- applicationId "com.httpsms"
- minSdk 28
- targetSdk 33
- versionCode 1
- versionName "${getGitHash()}"
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
-
- buildTypes {
- debug {
- manifestPlaceholders["sentryEnvironment"] = "development"
- }
- release {
- manifestPlaceholders["sentryEnvironment"] = "production"
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
- }
- namespace 'com.httpsms'
-}
-
-dependencies {
- implementation platform('com.google.firebase:firebase-bom:30.1.0')
- implementation 'com.google.firebase:firebase-analytics-ktx'
- implementation 'com.google.firebase:firebase-messaging-ktx'
- implementation 'com.squareup.okhttp3:okhttp:4.10.0'
- implementation 'com.jakewharton.timber:timber:5.0.1'
- implementation 'androidx.preference:preference-ktx:1.2.1'
- implementation 'androidx.work:work-runtime-ktx:2.7.1'
- implementation 'androidx.core:core-ktx:1.9.0'
- implementation "androidx.cardview:cardview:1.0.0"
- implementation 'com.beust:klaxon:5.5'
- implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'org.apache.commons:commons-text:1.9'
- implementation 'com.google.android.material:material:1.9.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.5'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
-}
diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts
new file mode 100644
index 000000000..f670b8bb7
--- /dev/null
+++ b/android/app/build.gradle.kts
@@ -0,0 +1,79 @@
+plugins {
+ id("com.android.application")
+ id("com.google.gms.google-services")
+ id("io.sentry.android.gradle") version "6.14.0"
+ id("org.jetbrains.kotlin.plugin.compose")
+}
+
+val gitHash = providers.exec {
+ commandLine("git", "rev-parse", "--short", "HEAD")
+}.standardOutput.asText.map { it.trim() }
+
+android {
+ compileSdk = 37
+
+ defaultConfig {
+ applicationId = "com.httpsms"
+ minSdk = 28
+ targetSdk = 37
+ versionCode = 1
+ versionName = gitHash.getOrElse("unknown")
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ getByName("debug") {
+ manifestPlaceholders["sentryEnvironment"] = "development"
+ }
+ getByName("release") {
+ manifestPlaceholders["sentryEnvironment"] = "production"
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ namespace = "com.httpsms"
+
+ buildFeatures {
+ buildConfig = true
+ compose = true
+ }
+}
+
+dependencies {
+ val composeBom = platform("androidx.compose:compose-bom:2026.06.01")
+ implementation(composeBom)
+ androidTestImplementation(composeBom)
+
+ implementation("androidx.compose.ui:ui")
+ implementation("androidx.compose.ui:ui-graphics")
+ implementation("androidx.compose.ui:ui-tooling-preview")
+ implementation("androidx.compose.material3:material3")
+ implementation("androidx.compose.material:material-icons-extended")
+ implementation("androidx.activity:activity-compose:1.13.0")
+ implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0")
+
+ implementation(platform("com.google.firebase:firebase-bom:34.16.0"))
+ implementation("com.journeyapps:zxing-android-embedded:4.3.0")
+ implementation("com.google.firebase:firebase-analytics")
+ implementation("com.google.firebase:firebase-messaging")
+ implementation("com.squareup.okhttp3:okhttp:5.4.0")
+ implementation("com.jakewharton.timber:timber:5.0.1")
+ implementation("androidx.preference:preference-ktx:1.2.1")
+ implementation("androidx.work:work-runtime-ktx:2.11.2")
+ implementation("androidx.core:core-ktx:1.19.0")
+ implementation("androidx.cardview:cardview:1.0.0")
+ implementation("com.beust:klaxon:5.6")
+ implementation("androidx.appcompat:appcompat:1.7.1")
+ implementation("org.apache.commons:commons-text:1.15.0")
+ implementation("com.google.android.material:material:1.14.0")
+ implementation("androidx.constraintlayout:constraintlayout:2.2.1")
+ implementation("com.googlecode.libphonenumber:libphonenumber:9.0.34")
+ implementation("com.klinkerapps:android-smsmms:5.2.6")
+ testImplementation("junit:junit:4.13.2")
+ androidTestImplementation("androidx.test.ext:junit:1.3.0")
+ androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
+}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 8a076fecc..86ca0a514 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -8,9 +8,11 @@
android:required="false" />
` + content + ``) + return formattedPayload, richPayload +} + +func indentEventPayloadJSON(payload string) (string, bool) { + var formatted bytes.Buffer + if err := json.Indent(&formatted, []byte(payload), "", " "); err != nil { + return payload, false + } + + return formatted.String(), true +} + +func highlightEventPayloadJSON(payload string) string { + var highlighted strings.Builder + highlighted.Grow(len(payload)) + + for index := 0; index < len(payload); { + switch { + case payload[index] == '"': + end := eventPayloadJSONStringEnd(payload, index) + style := jsonStringStyle + if eventPayloadNextNonSpace(payload, end) == ':' { + style = jsonKeyStyle + } + writeEventPayloadToken(&highlighted, style, payload[index:end]) + index = end + case payload[index] == '-' || isEventPayloadDigit(payload[index]): + end := index + 1 + // json.Indent already validated this as JSON, so this continuation set only sees JSON number bytes. + for end < len(payload) && isEventPayloadNumberCharacter(payload[end]) { + end++ + } + writeEventPayloadToken(&highlighted, jsonNumberStyle, payload[index:end]) + index = end + case strings.HasPrefix(payload[index:], "true"): + writeEventPayloadToken(&highlighted, jsonLiteralStyle, "true") + index += len("true") + case strings.HasPrefix(payload[index:], "false"): + writeEventPayloadToken(&highlighted, jsonLiteralStyle, "false") + index += len("false") + case strings.HasPrefix(payload[index:], "null"): + writeEventPayloadToken(&highlighted, jsonLiteralStyle, "null") + index += len("null") + default: + highlighted.WriteString(html.EscapeString(payload[index : index+1])) + index++ + } + } + + return highlighted.String() +} + +func eventPayloadJSONStringEnd(payload string, start int) int { + escaped := false + for index := start + 1; index < len(payload); index++ { + switch { + case escaped: + escaped = false + case payload[index] == '\\': + escaped = true + case payload[index] == '"': + return index + 1 + } + } + + return len(payload) +} + +func eventPayloadNextNonSpace(payload string, start int) byte { + for index := start; index < len(payload); index++ { + switch payload[index] { + case ' ', '\n', '\r', '\t': + continue + default: + return payload[index] + } + } + + return 0 +} + +func isEventPayloadDigit(value byte) bool { + return value >= '0' && value <= '9' +} + +func isEventPayloadNumberCharacter(value byte) bool { + return isEventPayloadDigit(value) || + value == '-' || + value == '+' || + value == '.' || + value == 'e' || + value == 'E' +} + +func writeEventPayloadToken(builder *strings.Builder, style string, token string) { + builder.WriteString(``) + builder.WriteString(html.EscapeString(token)) + builder.WriteString(``) +} diff --git a/api/pkg/emails/event_payload_formatter_test.go b/api/pkg/emails/event_payload_formatter_test.go new file mode 100644 index 000000000..9617ebb0e --- /dev/null +++ b/api/pkg/emails/event_payload_formatter_test.go @@ -0,0 +1,113 @@ +package emails + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFormatEventPayloadIndentsAndHighlightsJSON(t *testing.T) { + payload := `{"message":"hello","count":2,"ratio":1.5,"enabled":true,"disabled":false,"missing":null,"nested":{"value":"ok"}}` + + plain, rich := formatEventPayload(payload) + html := string(rich) + + assert.Equal(t, `{ + "message": "hello", + "count": 2, + "ratio": 1.5, + "enabled": true, + "disabled": false, + "missing": null, + "nested": { + "value": "ok" + } +}`, plain) + assert.Contains(t, html, `"message"`) + assert.Contains(t, html, `"hello"`) + assert.Contains(t, html, `2`) + assert.Contains(t, html, `1.5`) + assert.Contains(t, html, `true`) + assert.Contains(t, html, `false`) + assert.Contains(t, html, `null`) + assert.Contains(t, html, `white-space:pre-wrap`) +} + +func TestFormatEventPayloadEscapesPayloadHTML(t *testing.T) { + plain, rich := formatEventPayload(`{"message":"&"}`) + html := string(rich) + + assert.Contains(t, plain, ` + + +
+ httpSMS is an + open source + application that converts your android phone into an SMS gateway so you + can send and receive SMS messages using a simple HTTP API. +
++ Enter your email address to reset your password +
++ By continuing, you are indicating that you accept our + + Terms of Service + + and + + Privacy Policy. +
++ Start sending messages +
++ Install the mobile app on your Android phone to start sending messages. + You can also + message us on Discord + to help set things up. +
++ {{ phoneCountry(phonesStore.owner) }} +
+{{ error.message }}
+
+
+
+ + Your next bill is for ${{ plan.price }} on + {{ + new Date( + authStore.user.subscription_renews_at!, + ).toLocaleDateString() + }} +
++ You are on the life time plan which costs + ${{ plan.price }} +
++ You will be downgraded to the FREE plan on + {{ + new Date( + authStore.user.subscription_ends_at!, + ).toLocaleDateString() + }} +
++ {{ formatDecimal(totalMessages) }}/{{ + formatDecimal(plan.messagesPerMonth) + }} + messages +
++ You will be downgraded to the free plan at the end + of the current billing period on + {{ + new Date( + authStore.user.subscription_renews_at!, + ).toLocaleDateString() + }} +
++ Send and receive 5,000 to 20,000 messages per month +
++ Send and receive 50,000 to 200,000 messages per + month +
+
+ This is the summary of the sent messages and received messages
+ from
+
Messages Sent
+Messages Received
++ This is a list of your last 10 subscription payments made using + our payment provider + + Lemon Squeezy. +
++ Summary of all the sent and received messages in the past 12 + billing periods +
++ We have added support for end-to-end encryption for SMS messages so + that no one can see the content of the messages you send using httpSMS + except you. +
++ You setup an encryption key which you use to encrypt your messages + before making an API request to httpSMS and you also use the same key + to decrypt the messages you receive from httpSMS via our + webhook events. We are using the + AES 256 + encryption algorithm to encrypt and decrypt the messages. +
+ ++ ⬇️ Download and install + the httpSMS Android app on your phone and set you encryption key under + the App Settings page of the app. +
++ We use the AES-256 encryption algorithm to encrypt the SMS messages. + This algorithm requires a an encryption key which is 256 bits to work + around this, we will hash any encryption key you set on the mobile app + using the sha-256 algorithm so that it will always produce a key which + is 256 bits. +
++ The AES algorithm also has an initialization vector (IV) parameter + which is used to ensure that the same value encrypted multiple times + will not produce the same encrypted value. The IV is 16 bits and it is + appended to the encrypted message before encoding it in base64. +
++ When you use our client libraries it will automatically take care of + encrypting your message so you don't have to deal with creating the + initialization vector and encoding the payload yourself. +
+ +import HttpSms from "httpsms"
+
+const client = new HttpSms("" /* API Key from https://httpsms.com/settings */);
+
+const key = "Password123";
+
+const encryptedMessage = client.cipher.encrypt(key, "This is a sample text message");
+
+// The encrypted message looks like this, note that you will get a different encrypted message when you run this code on your computer
+// Qk3XGN5+Ax38Ig01m4AqaP6Y0b0wYpCXtx59sU23uVLWUU/c7axF7LozDg==
+ import "github.com/NdoleStudio/httpsms-go"
+
+client := htpsms.New(htpsms.WithAPIKey(""/* API Key from https://httpsms.com/settings */))
+
+key := "Password123" // use the same key on the Android app
+encryptedMessage := client.Cipher.Encrypt(key, "This is a test text message")
+
+// The encrypted message looks like this, note that you will get a different encrypted message when you run this code on your computer
+// Qk3XGN5+Ax38Ig01m4AqaP6Y0b0wYpCXtx59sU23uVLWUU/c7axF7LozDg==
+
+ After generating the encrypted message payload, you can send it
+ directly using the httpSMS API. Make sure to set
+ encrypted: true in the JSON request payload so that
+ httpSMS knows that the message is encrypted and it will be decoded in
+ the Android app before sending to your recipient.
+
import HttpSms from "httpsms"
+
+client.messages.postSend({
+ content: encryptedMessage,
+ from: '+18005550199',
+ encrypted: true,
+ to: '+18005550100',
+})
+.then((message) => {
+ console.log(message.id); // log the ID of the sent message
+});
+ import "github.com/NdoleStudio/httpsms-go"
+
+client.Messages.Send(context.Background(), &httpsms.MessageSendParams{
+ Content: encryptedMessage,
+ From: "+18005550199",
+ To: "+18005550100",
+ Encrypted: true,
+})
+ + When you make the API request, the message will be decrypted before + sending to the recipient. This is a screenshot of the SMS message + which is sent to the recipient. +
+
+ When your android phone receives a new message, it will be encrypted
+ with the encryption Key on your Android phone before it is delivered
+ to your server's webhook endpoint. You can configure webhooks by
+ following
+
import HttpSms from "httpsms"
+
+const client = new HttpSms("" /* API Key from https://httpsms.com/settings */);
+
+// The payload in the webhook HTTP request looks like this
+/*
+{
+ "specversion": "1.0",
+ "id": "8dca3b0a-446a-4a5d-8d2a-95314926c4ed",
+ "source": "/v1/messages/receive",
+ "type": "message.phone.received",
+ "datacontenttype": "application/json",
+ "time": "2024-01-21T12:27:29.1605708Z",
+ "data": {
+ "message_id": "0681b838-4157-44bb-a4ea-721e40ee7ca7",
+ "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2",
+ "owner": "+37253920216",
+ "encrypted": true,
+ "contact": "+37253920216",
+ "timestamp": "2024-01-21T12:27:17.949Z",
+ "content": "bdmZ7n6JVf/ST+SoNlSaOGUL1DcL5705ETw8GAB4llYBgE9HOOL+Pu/h+w==",
+ "sim": "SIM1"
+ }
+}
+*/
+
+const encryptedMessage = "bdmZ7n6JVf/ST+SoNlSaOGUL1DcL5705ETw8GAB4llYBgE9HOOL+Pu/h+w==" // get the encrypted message from the request payload
+const encryptionkey = "Password123" // use the same key on the Android app
+const decryptedMessage = client.cipher.decrypt(encryptionkey, encryptedMessage)
+
+// This is a test text message
+ import "github.com/NdoleStudio/httpsms-go"
+
+client := htpsms.New(htpsms.WithAPIKey(/* API Key from https://httpsms.com/settings */))
+
+// The payload in the webhook HTTP request looks like this
+/*
+{
+ "specversion": "1.0",
+ "id": "8dca3b0a-446a-4a5d-8d2a-95314926c4ed",
+ "source": "/v1/messages/receive",
+ "type": "message.phone.received",
+ "datacontenttype": "application/json",
+ "time": "2024-01-21T12:27:29.1605708Z",
+ "data": {
+ "message_id": "0681b838-4157-44bb-a4ea-721e40ee7ca7",
+ "user_id": "XtABz6zdeFMoBLoltz6SREDvRSh2",
+ "owner": "+37253920216",
+ "encrypted": true,
+ "contact": "+37253920216",
+ "timestamp": "2024-01-21T12:27:17.949Z",
+ "content": "bdmZ7n6JVf/ST+SoNlSaOGUL1DcL5705ETw8GAB4llYBgE9HOOL+Pu/h+w==",
+ "sim": "SIM1"
+ }
+}
+*/
+
+encryptedMessage = "bdmZ7n6JVf/ST+SoNlSaOGUL1DcL5705ETw8GAB4llYBgE9HOOL+Pu/h+w==" // get the encrypted message from the request payload
+encryptionkey := "Password123" // use the same key on the Android app
+decryptedMessage := client.Cipher.Decrypt(encryptionkey, encryptedMessage)
+
+// This is a test text message
+ + Congratulations, you have successfully configured your Android phone + to send and receive SMS messages with end-to-end encryption. Don't + hesitate to contact us if you face any problems while following this + guide. +
+ +
+ You can now program your android phone to forward messages received on
+ your phone to your server and trigger powerful automations with tools
+ like Zapier and IFTTT. I created an open source application called
+
+ Create an account on the httpSMS web application and copy your API key
+ from the settings page.
+
+ ⬇️ Download and install + the httpSMS android app on your phone and sign in using your API KEY + which you copied above. This app listens for SMS messages received on + your android phone. +
+
+ Once the application has been installed, it will be listening for SMS
+ messages received on the android phone. You can configure the
+ application to sent this SMS message to your server URL using a
+ webhook. You can configure this URL under the settings page in the
+ httpSMS application
+
+ Congratulations, you have successfully set up SMS forwarding from your + Android phone to a webhook! This powerful automation tool can help you + streamline your business workflow and save you time and effort. +
++ You can also trigger the httpSMS application to send an SMS a simple + API. You can find more information on the documentation page at + https://docs.httpsms.com +
+Until the next time✌️
+ +
+ In Android 15 (Vanilla Ice Cream), the
+ android.permission.SEND_SMS and
+ android.permission.RECEIVE_SMS permissions are now hard
+ restricted and cannot be granted
+ via the runtime permissions interface.
+
SEND_SMS and
+ RECEIVE_SMS permissions will allow an Android app to be
+ able to read and send SMS messages on your phone. Make sure you trust
+ the application before allowing these permissions.
+ + Long press the icon of the android app which you want to grant the + permission and select "App info" +
+
+ On the App Info page, click on the menu button
+
+ Once you have allowed the restricted settings from step 2 above, You + can navigate to Permissions ➡️ SMS and tap the Allow button to + grant SMS permissions to the android app. +
++ Congratulations, you have successfully configured SMS permissions on + your Android app. Don't hesitate to contact us if you face any + problems while following this guide. +
+ ++ Send personalized SMS messages to multiple phone numbers for less than + $0.002 per SMS message. You can also configure every SMS + message in your Excel spreadsheet so they are unique for each + recipient phone number. +
+ +
+ Create an account on
+
+ ⬇️ Download and install + the httpSMS android app on your phone and sign in using your API KEY + which you copied above. This app listens for SMS messages received on + your android phone. +
+
+ Download the
+ httpSMS Excel file template
+ and edit it with your favorite spreadsheet software e.g Excel, Google
+ Sheets, Open Office etc. Fill in the phone number which you registered
+ in httpSMS in the FromPhoneNumber column and fill in the
+ number of the recipient of the SMS in the
+ ToPhoneNumber column. Also add the SMS which you want to
+ send in the message in the Content column.
+
FromPhoneNumber from step 2
+ above in your Excel file
+
+ Visit the
+
+ Don't hesitate to + contact us + if you face any issues sending bulk SMS messages from your Excel files + by following this tutorial. +
+Until the next time✌️
+ ++ {{ article.description }} +
++ Send personalized SMS messages to your users in bulk using your + Android phone. The good news is, you don't have to write a single + piece of code, just upload your CSV file and we will take care of the + rest. +
+ +
+ CSV is an abbreviation for comma-separated values. A CSV file allows
+ data to be saved in a table structured format using a comma
+ , to separate the various cells of a table and a new line
+ to separate the various rows in the table. CSV files can be used with
+ any spreadsheet program, such as Microsoft Excel, Open Office Calc, or
+ Google Sheets.
+
+ Create an account on
+
+ ⬇️ Download and install + the httpSMS android app on your phone and sign in using your API KEY + which you copied above. This app listens for SMS messages received on + your android phone. +
+
+ Download the
+ httpSMS CSV file template
+ and edit it with your favorite spreadsheet software e.g Excel, Google
+ Sheets or even a text editor like notepad. Fill in the phone number
+ which you registered in httpSMS in the
+ FromPhoneNumber column and fill in the number of the
+ recipient of the SMS in the ToPhoneNumber column. Also
+ add the SMS which you want to send in the message in the
+ Content column.
+
FromPhoneNumber from step 2
+ above in your CSV file
+
+ Visit the
+
+ Don't hesitate to + contact us + if you face any issues sending bulk SMS messages from your CSV files + by following this tutorial. +
+Until the next time✌️
+ ++ In an era dominated by social media, instant messaging apps, and + ever-evolving communication technologies, it's easy to overlook the + humble yet remarkably resilient Short Message Service (SMS). Since its + inception in the 1990s, SMS has stood the test of time, remaining one + of the most widely used and reliable means of mobile communication. +
++ Whether you're a business owner looking to optimize your communication + strategy, a developer seeking to integrate SMS functionality into your + applications, or simply intrigued by the enduring charm of SMS, this + article will explain how to setup your Android phone to send SMS + messages. +
+ +
+ Create an account on
+
+ ⬇️ Download and install + the httpSMS android app on your phone and sign in using your API KEY + which you copied above. This app listens for SMS messages received on + your android phone. +
+
+ Now that you have setup your android phone correctly on httpSMS, you
+ can write the python code below in a new file named
+ send_sms.py. This code will send and SMS and after
+ running the script via your Android phone to the recipient phone
+ number specified in the payload.
+
api_key from step 1 and also
+ use the correct to and from phone numbers in
+ the payload variable.
+ import requests
+import json
+
+api_key = "" # Get API Key from https://httpsms.com/settings
+
+url = 'https://api.httpsms.com/v1/messages/send'
+
+headers = {
+ 'x-api-key': api_key,
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+}
+
+payload = {
+ "content": "This is a sample text message sent via python",
+ "from": "+18005550199", # This is the phone number of your android phone
+ "to": "+18005550100" # This is the recipient phone number
+}
+
+response = requests.post(url, headers=headers, data=json.dumps(payload))
+
+print(json.dumps(response.json(), indent=4))
+
+ Run the code above with the command
+ python send_sms.py and check the phone specified in the
+ to field of the payload to verify that the
+ message has been received successfully.
+
+ Congratulations, you have successfully configured your android phone + to send SMS messages via python. You can now reuse this code to send + SMS messages from your python applications. +
+
+ If you are also interested in forwarding incoming SMS from your
+ android phone to your server, checkout our
+
Until the next time✌️
+ ++ Automate sending personalized SMS messages each time a new row is + added to your Google Sheets document using Zapier. You don't need to + write any code to make this happen and you can personalize the SMS + messages which are sent out. +
+ ++ Create a new Zap on Zapier and select Google Sheets as the trigger. + The event name should be "New Spreadsheet Row" if you want to + send an SMS message every time a new row is added to your Google + Sheets document. +
++ On the Zap, select the Spreadsheet which you have on google + drive and make sure to select the correct Worksheet. +
++ An action is what happens after the trigger. In this case, we want to + send an SMS message to the customer who made the purchase. Select + Webhooks By Zapier as the action app and select + Custom Request as the action event. +
+
+ On the Action section in Zapier, set the Method to
+ Post. Set the URL to
+ https://api.httpsms.com/v1/messages/send. Set the
+ Data Pass-Through to false. In the Data
+ field, add the following JSON payload.
+
{
+ "content": "Hello [Name]\nThanks for ordering [Product] via our shopify store. Your order will be shipped today!",
+ "from": "+18005550199",
+ "to": "[ToPhoneNumber]"
+}
+ [Name] variable contains the name of the customer on the
+ spreadsheet. [Product] contains the name of the product
+ which was bought and [ToPhoneNumber] contains the phone
+ number of the customer who made the purchase. You can use your own
+ custom message with your own set of variables according to your
+ spreadsheet. Change the from field to the phone number
+ which you registered on httpsms.com.
+
+ On the headers section add a new header called
+ x-api-key and the value of this header should be your API
+ key on
+
+ Also add a new header called Content-Type and the value
+ of this header should be application/json
+
+ The final configuration of the action should look like the screenshot + below. +
++ Publish your zap and you will automatically trigger httpsms to send an + SMS to your customer when ever you add a new row in the google sheet. + Don't hesitate to + contact us + if you face any issues configuring your zap to send SMS messages from + your Google Sheets by following this tutorial. +
+Until the next time✌️
+ +
+ Fill in our bulk SMS
+ CSV template
+ or our
+ Excel template
+ and upload it here to send your SMS messages to multiple
+ recipients at once. You can also configure
+
+ Your 10 most recent bulk SMS uploads are shown below, including a + delivery status breakdown for each batch. Click on a row to see + individual messages on the search page. +
++ Use httpSMS as a lightweight CRM by adding your contacts here. Your + message threads will show contact names instead of phone numbers, + making conversations easier to recognize and manage. Add contacts + individually, or fill in our + CSV template + and upload it to import your contact list in bulk. +
+ ++ {{ + searchTerm + ? 'No contacts match your search' + : 'No contacts yet' + }} +
++ {{ + searchTerm + ? 'Try a different name, phone number or email.' + : 'Add your first contact or import them from a CSV file.' + }} +
+
+ Download the
+ CSV template, fill it in and upload it here. Separate multiple emails or phone
+ numbers within a cell using a semicolon (;).
+
We couldn't import your file:
++ Every 15 minutes, the httpSMS app on your Android phone sends a + heartbeat event to the httpsms API to show that it is alive. The + reason for this is because the Android operating system sometimes + kills an application to save battery + https://dontkillmyapp.com. +
++ If httpSMS doesn't get any heartbeat event in a 1-hour interval, + you will get an email notification about it so you can check if + there is an issue with your Android phone. +
++ The table below shows the last 100 heartbeat events received from + the httpSMS app on your Android phone. +
++ ⚡Trusted by 23,273+ users who send/receive more than + 500,000 messages per month. +
+
+
+ import HttpSms from 'httpsms'
+
+const client = new HttpSms('' /* Get the API Key from https://httpsms.com/settings */);
+
+client.messages.postSend({
+ content: 'This is a sample text message',
+ from: '+18005550199', // Put the correct phone number here
+ to: '+18005550100', // Put the correct phone number here
+})
+.then((message) => {
+ console.log(message.id); // log the ID of the sent message
+})
+ <?php
+$apiKey = "Get API Key from https://httpsms.com/settings";
+
+$options = array(
+ 'http' => array(
+ 'method' => 'POST',
+ 'content' => json_encode( [
+ 'content' => 'This is a sample text message',
+ 'from' => "+18005550199",
+ 'to' => "+18005550100"
+ ]),
+ 'header'=> "Content-Type: application/json\r\n" .
+ "Accept: application/json\r\n" .
+ "x-api-key: $apiKey\r\n"
+ )
+);
+
+$context = stream_context_create( $options );
+$result = file_get_contents( "https://api.httpsms.com/v1/messages/send", false, $context );
+
+echo $result;
+ import requests
+import json
+
+api_key = "Get API Key from https://httpsms.com/settings"
+
+url = 'https://api.httpsms.com/v1/messages/send'
+
+headers = {
+ 'x-api-key': api_key,
+ 'Accept': 'application/json',
+ 'Content-Type': 'application/json'
+}
+
+payload = {
+ "content": "This is a sample text message",
+ "from": "+18005550199",
+ "to": "+18005550100"
+}
+
+response = requests.post(url, headers=headers, data=json.dumps(payload))
+
+print(json.dumps(response.json(), indent=4))
+ import "github.com/NdoleStudio/httpsms-go"
+
+client := htpsms.New(htpsms.WithAPIKey(/* API Key from https://httpsms.com/settings */))
+
+client.Messages.Send(context.Background(), &httpsms.MessageSendParams{
+ Content: "This is a sample text message",
+ From: "+18005550199",
+ To: "+18005550100",
+})
+ var client = HttpClient.newHttpClient();
+var apiKey = "Get API Key from https://httpsms.com/settings";
+
+var payload = """
+ {
+ "content": "This is a sample text message",
+ "from": "+18005550199",
+ "to": "+18005550100"
+ }
+ """;
+
+var request = HttpRequest.newBuilder()
+ .uri(URI.create("https://api.httpsms.com/v1/messages/send"))
+ .header("accept", "application/json")
+ .header("Content-Type", "application/json")
+ .header("x-api-key", apiKey)
+ .POST(HttpRequest.BodyPublishers.ofString(payload))
+ .build();
+
+var response = client.send(request, HttpResponse.BodyHandlers.ofString());
+System.out.println(response.body());
+ curl --location --request POST 'https://api.httpsms.com/v1/messages/send' \
+--header 'x-api-key: Get API Key from https://httpsms.com/settings' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "from": "+18005550199",
+ "to": "+18005550100",
+ "content": "This is a sample text message"
+}'
+ var client = new HttpClient();
+client.DefaultRequestHeaders.Add("x-api-key", ""/* Get API Key from https://httpsms.com/settings */);
+
+var response = await client.PostAsync(
+ "https://api.httpsms.com/v1/messages/send",
+ new StringContent(
+ JsonSerializer.Serialize(new {
+ from = "+18005550199",
+ To = "+18005550100",
+ Content = "This is a sample text message",
+ }),
+ Encoding.UTF8,
+ "application/json"
+ )
+);
+
+Console.WriteLine(await response.Content.ReadAsStringAsync());
+ + Monthly +
+
+ Yearly
+
+ Try sending and receiving SMS on your hobby websites and + experiments. +
++ $0 +
++ No credit card required +
+
+
+
+
+
+ Send and receive more SMS messages like a pro with advanced + features. +
++ $10/month +
++ $100/year +
++ or $100 per year +
++ or $8.33 per month +
+
+
+
+
+
+ Send and receive up to {{ planMessages }} SMS messages like a + power user. +
++ ${{ planMonthlyPrice }}/month +
++ ${{ planYearlyPrice }}/year +
++ or ${{ planYearlyPrice }} per year +
++ or ${{ planYearlyMonthlyPrice }} per month +
+
+
+
+
+
Joysankar M.
++ httpSMS is free platform which transforms your phone into an sms + server! It has no hard limit also. It is an + innovative idea, I have not seen such tech before. If you + have an sms active pack in your phone then good to go + with httpSMS. +
+Edmund Ciego
++ "Outstanding product. Literally have been using this for + years since we don't have an sms gateways that can handle http + requests costing less than 50 cent per sms in my Country. + Love the product and the support! Great work Arnold!" +
++ If you still cannot find the answer to your question, + send us an email or ask in + our Discord channel. +
++ The httpSMS application works only on Android phones at the + moment since Apple doesn't allow you to install a custom SMS + messaging app. +
++ The httpSMS Android app works from Android 9 (Pie) and above. + So you can install the application on your old Android phone + which you don't use anymore. +
++ We do have packages that allow up to 200,000 SMS messages per + month but you can + send us an email if + you will like to send more messages so we create a custom plan + just for you. +
++ No you cannot. When you send an SMS message using the httpSMS + app it uses your SIM card to send the message so the recipient + will see your phone number as the sender of the SMS. You + cannot use your brand name as the sender ID. +
+
+ Join 23,273+ users who send/receive more than
+
+ 500,000 messages per month
+
+ Enter the recipient's phone number and your message below, and
+ we'll deliver a real SMS it through your connected Android phone.
+ You can also text a short code like
+
+ If you have multiple phones, you can create unique phone API keys
+ for your different Android phones. These API keys can only be used
+ on the specific mobile phone when it calls the httpSMS server for
+ specific actions like sending heartbeats, registering received
+ messages, delivery reports etc. If you want to interact with the
+ full
+ httpSMS API, use the API key under your account settings page instead
+
{{ formatPhoneNumber(activePhoneNumber) }} from your
+ phone API key. You will have to logout and login again on the
+ httpSMS Android app on the phone which is currently using this
+ API key.
+
- Ndole Studio built the HTTP SMS service as an open source project.
- This SERVICE is provided by Ndole Studio and is intended for use as
- is. This page is used to inform visitors regarding our policies with
- the collection, use, and disclosure of Personal Information if anyone
+
+ Ndole Studio built the httpSMS service as an open source project. This
+ SERVICE is provided by Ndole Studio and is intended for use as is.
+ This page is used to inform visitors regarding our policies with the
+ collection, use, and disclosure of Personal Information if anyone
decided to use our Service. If you choose to use our Service, then you
agree to the collection and use of information in relation to this
policy. The Personal Information that we collect is used for providing
and improving the Service. We will not use or share your information
with anyone except as described in this Privacy Policy. The terms used
in this Privacy Policy have the same meanings as in our Terms and
- Conditions, which are accessible at HTTP SMS unless otherwise defined
+ Conditions, which are accessible at httpSMS unless otherwise defined
in this Privacy Policy.
+
+
For a better experience, while using our Service, we may require you
to provide us with certain personally identifiable information,
- including but not limited to email,full name. The information that we
+ including but not limited to email, full name. The information that we
request will be retained by us and used as described in this privacy
policy.
- HTTP SMS does use third-party services that may collect information
+
+ httpSMS does use third-party services that may collect information
used to identify you. Link to the privacy policy of third-party
- service providers used by HTTP SMS
+ service providers used by httpSMS:
+
+
We want to inform you that whenever you use our Service, in a case of
an error in the app we collect data and information (through
third-party products) on your phone and computer called Log Data. This
Log Data may include information such as your device Internet Protocol
- (“IP”) address, device name, operating system version, the
+ ('IP') address, device name, operating system version, the
configuration of the app when utilizing our Service, the time and date
of your use of the Service, and other statistics.
+
+
Cookies are files with a small amount of data that are commonly used
as anonymous unique identifiers. These are sent to your browser from
the websites that you visit and are stored on your device's internal
- memory. This Service does not use these “cookies” explicitly. However,
- the app may use third-party code and libraries that use “cookies” to
+ memory. This Service does not use these 'cookies' explicitly. However,
+ the app may use third-party code and libraries that use 'cookies' to
collect information and improve their services. You have the option to
either accept or refuse these cookies and know when a cookie is being
sent to your device. If you choose to refuse our cookies, you may not
be able to use some portions of this Service.
+
+
We may employ third-party companies and individuals due to the
following reasons:
+
We want to inform users of this Service that these third parties have
access to their Personal Information. The reason is to perform the
tasks assigned to them on our behalf. However, they are obligated not
to disclose or use the information for any other purpose.
+
+
We value your trust in providing us your Personal Information, thus we
are striving to use commercially acceptable means of protecting it.
But remember that no method of transmission over the internet, or
method of electronic storage is 100% secure and reliable, and we
cannot guarantee its absolute security.
+
+
This Service may contain links to other sites. If you click on a
third-party link, you will be directed to that site. Note that these
external sites are not operated by us. Therefore, we strongly advise
@@ -124,8 +145,9 @@
over and assume no responsibility for the content, privacy policies,
or practices of any third-party sites or services.
+
+
These Services do not address anyone under the age of 13. We do not
knowingly collect personally identifiable information from children
under 13 years of age. In the case we discover that a child under 13
@@ -134,16 +156,22 @@
that your child has provided us with personal information, please
contact us so that we will be able to do the necessary actions.
+
+
We may update our Privacy Policy from time to time. Thus, you are
advised to review this page periodically for any changes. We will
notify you of any changes by posting the new Privacy Policy on this
page.
This policy is effective as of 2022-10-09
+
+ This policy is effective as of 2022-10-09
+
If you have any questions or suggestions about our Privacy Policy, do
not hesitate to contact us at
support@httpsms.com.
Privacy Policy
+ Information Collection and Use
-
+ Information Collection and Use
+
+
+
- Log Data
- Log Data
+ Cookies
- Cookies
+ Service Providers
- Service Providers
+
+
- Security
- Security
+ Links to Other Sites
- Links to Other Sites
+ Children’s Privacy
- Children's Privacy
+ Changes to This Privacy Policy
-
+ Changes to This Privacy Policy
+
+ Contact Us
- Contact Us
+
+ On this page, you can search all your messages by phone number, + message type, and message status and even using the content of the + SMS message. You will also be able to bulk delete messages and + even export your messages in a CSV file. +
+{{ item.content }}
+
+
+ Use your API Key in the
+ Scan this QR code with the + httpSMS app + on your Android phone to login. +
+ ++ Webhooks allow us to send events to your server for example when + the android phone receives an SMS message we can forward the + message to your server. +
+
+ Send and receive SMS messages without leaving your discord server
+ with the httpSMS discord app using the
+
+ List of mobile phones which are registered for sending and + receiving SMS messages. +
++ Create availability schedules and attach them to each phone. + Outgoing messages sent outside the schedule window are queued and + delivered when the schedule opens according to your + configured send rate. +
++ Manage the email notifications which you receive from httpSMS. + Feel free to turn on/off individual notifications anytime so you + don't get overloaded with emails +
+
+ Your messages are permanently deleted once they exceed the max
+ retention period below, counted from when the message was sent or
+ received. You can always delete your messages manually on the
+
+ You cannot delete your account because you have an active
+ subscription on httpSMS.
+
+ You can delete all your data on httpSMS by clicking the button + below. This action is irreversible and all your data will + be permanently deleted from the httpSMS database instantly and it + cannot be recovered. +
++ Click the button below to add the httpSMS bot to your discord + server. You need to do this so we can have permission to send + and receive messages on your discord server. +
+
+
By downloading or using the app and using the HTTP SMS service, these
terms will automatically apply to you – you should make sure therefore
- that you read them carefully before using the app. You’re not allowed
+ that you read them carefully before using the app. You're not allowed
to copy or modify the app, any part of the app, or our trademarks in
- any way. You’re not allowed to attempt to extract the source code of
- the app, and you also shouldn’t try to translate the app into other
+ any way. You're not allowed to attempt to extract the source code of
+ the app, and you also shouldn't try to translate the app into other
languages or make derivative versions. The app itself, and all the
trademarks, copyright, database rights, and other intellectual
property rights related to it, still belong to Ndole Studio.
+
Ndole Studio is committed to ensuring that the app is as useful and
efficient as possible. For that reason, we reserve the right to make
changes to the app or to charge for its services, at any time and for
any reason. We will never charge you for the app or its services
- without making it very clear to you exactly what you’re paying for.
+ without making it very clear to you exactly what you're paying for.
+
The HTTP SMS app stores and processes personal data that you have
- provided to us, to provide our Service. It’s your responsibility to
+ provided to us, to provide our Service. It's your responsibility to
keep your phone and access to the app secure. We therefore recommend
that you do not jailbreak or root your phone, which is the process of
removing software restrictions and limitations imposed by the official
operating system of your device. It could make your phone vulnerable
- to malware/viruses/malicious programs, compromise your phone’s
- security features and it could mean that the HTTP SMS app won’t work
+ to malware/viruses/malicious programs, compromise your phone's
+ security features and it could mean that the HTTP SMS app won't work
properly or at all.
+
HTTP SMS does use third-party services that declare their Terms and
Conditions. Link to Terms and Conditions of third-party service
- providers used by the app
+ providers used by the app:
+
You should be aware that there are certain things that Ndole Studio
will not take responsibility for. Certain functions of the app will
require the app to have an active internet connection. The connection
can be Wi-Fi or provided by your mobile network provider, but Ndole
Studio cannot take responsibility for the app not working at full
- functionality if you don’t have access to Wi-Fi, and you don’t have
+ functionality if you don't have access to Wi-Fi, and you don't have
any of your data allowance left.
- If you’re using the app outside of an area with Wi-Fi, you should
+
+ If you're using the app outside of an area with Wi-Fi, you should
remember that the terms of the agreement with your mobile network
provider will still apply. As a result, you may be charged by your
mobile provider for the cost of data for the duration of the
connection while accessing the app, or other third-party charges. In
- using the app, you’re accepting responsibility for any such charges,
+ using the app, you're accepting responsibility for any such charges,
including roaming data charges if you use the app outside of your home
territory (i.e. region or country) without turning off data roaming.
- If you are not the bill payer for the device on which you’re using the
+ If you are not the bill payer for the device on which you're using the
app, please be aware that we assume that you have received permission
from the bill payer for using the app.
+
Along the same lines, Ndole Studio cannot always take responsibility
for the way you use the app i.e. You need to make sure that your
- device stays charged – if it runs out of battery and you can’t turn it
+ device stays charged – if it runs out of battery and you can't turn it
on to avail the Service, Ndole Studio cannot accept responsibility.
- With respect to Ndole Studio’s responsibility for your use of the app,
- when you’re using the app, it’s important to bear in mind that
+
+ With respect to Ndole Studio's responsibility for your use of the app,
+ when you're using the app, it's important to bear in mind that
although we endeavor to ensure that it is updated and correct at all
times, we do rely on third parties to provide information to us so
that we can make it available to you. Ndole Studio accepts no
liability for any loss, direct or indirect, you experience as a result
of relying wholly on this functionality of the app.
+
At some point, we may wish to update the app. The app is currently
- available on Android – the requirements for the system(and for any
+ available on Android – the requirements for the system (and for any
additional systems we decide to extend the availability of the app to)
- may change, and you’ll need to download the updates if you want to
+ may change, and you'll need to download the updates if you want to
keep using the app. Ndole Studio does not promise that it will always
update the app so that it is relevant to you and/or works with the
Android version that you have installed on your device. However, you
promise to always accept updates to the application when offered to
- you, We may also wish to stop providing the app, and may terminate use
+ you. We may also wish to stop providing the app, and may terminate use
of it at any time without giving notice of termination to you. Unless
we tell you otherwise, upon any termination, (a) the rights and
licenses granted to you in these terms will end; (b) you must stop
using the app, and (if needed) delete it from your device.
+
We may update our Terms and Conditions from time to time. Thus, you
are advised to review this page periodically for any changes. We will
notify you of any changes by posting the new Terms and Conditions on
this page.
These terms and conditions are effective as of 2022-10-09
+
+ These terms and conditions are effective as of 2022-10-09
+
If you have any questions or suggestions about our Terms and
Conditions, do not hesitate to contact us at
support@httpsms.com.
Terms and Conditions
+
+
-
+
+
Changes to This Terms and Conditions
- Contact Us
- Contact Us
+
+ Don't hesitate to + message us on Discord + if you have any questions +
+code')
+ })
+
+ await t.test('wraps multiline triple-backtick code blocks', () => {
+ assert.equal(
+ formatWhatsappText('```\nline one\nline two\n```'),
+ '\nline one\nline two\n',
+ )
+ })
+
+ await t.test('does not reformat markdown characters inside code', () => {
+ assert.equal(formatWhatsappText('`a *b* c`'), 'a *b* c')
+ })
+})
+
+test('formatWhatsappText - links', async (t) => {
+ await t.test('linkifies a raw URL', () => {
+ assert.equal(
+ formatWhatsappText('visit https://example.com today'),
+ 'visit https://example.com today',
+ )
+ })
+
+ await t.test('strips unbalanced trailing punctuation from a URL', () => {
+ assert.equal(
+ formatWhatsappText('Check this out (https://example.com).'),
+ 'Check this out (https://example.com).',
+ )
+ })
+
+ await t.test(
+ 'keeps a balanced trailing parenthesis as part of the URL',
+ () => {
+ assert.equal(
+ formatWhatsappText('See https://example.com/page_(v2) for details.'),
+ 'See https://example.com/page_(v2) for details.',
+ )
+ },
+ )
+
+ await t.test(
+ 'preserves a legitimate trailing marker character that is part of the URL',
+ () => {
+ assert.equal(
+ formatWhatsappText('Download https://example.com/file_name_ now'),
+ 'Download https://example.com/file_name_ now',
+ )
+ },
+ )
+
+ await t.test('bolds a URL wrapped in asterisks', () => {
+ assert.equal(
+ formatWhatsappText('*https://example.com*'),
+ 'https://example.com',
+ )
+ })
+})
+
+test('formatWhatsappText - escaping and placeholders', async (t) => {
+ await t.test('escapes HTML special characters', () => {
+ assert.equal(
+ formatWhatsappText(''),
+ '<script>alert(1)</script>',
+ )
+ })
+
+ await t.test(
+ 'does not let literal placeholder-like text leak a link into the output',
+ () => {
+ const input = 'no links here, just text'
+ assert.equal(formatWhatsappText(input), input)
+ },
+ )
+
+ await t.test('two calls do not interfere with each other', () => {
+ const first = formatWhatsappText('visit https://a.example today')
+ const second = formatWhatsappText('visit https://b.example today')
+ assert.match(first, /href="https:\/\/a\.example"/)
+ assert.match(second, /href="https:\/\/b\.example"/)
+ assert.doesNotMatch(first, /https:\/\/b\.example/)
+ })
+})
diff --git a/web/app/utils/whatsapp-format.ts b/web/app/utils/whatsapp-format.ts
new file mode 100644
index 000000000..202a12355
--- /dev/null
+++ b/web/app/utils/whatsapp-format.ts
@@ -0,0 +1,200 @@
+/**
+ * Returns true when the given phone notification token is a URL (HTTP notification
+ * transport) instead of an FCM token.
+ */
+export function isUrlNotificationToken(
+ fcmToken?: string | null | undefined,
+): boolean {
+ if (!fcmToken) {
+ return false
+ }
+ return fcmToken.trim().toLowerCase().startsWith('https://')
+}
+
+function escapeHtml(text: string): string {
+ return text
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
+}
+
+// Character class (as a regex source string) that is treated as a valid
+// boundary around a formatting marker: whitespace, common punctuation, or
+// the start/end of the string.
+// Other formatting markers and generated tags (<>) also count so that nested
+// formatting such as `_*text*_` works.
+const BOUNDARY_CHARS = String.raw`\s.,!?;:'"()\[\]{}<>*_~-`
+
+function withBoundaries(pattern: string): RegExp {
+ return new RegExp(
+ `(?<=^|[${BOUNDARY_CHARS}])${pattern}(?=$|[${BOUNDARY_CHARS}])`,
+ 'g',
+ )
+}
+
+const CODE_BLOCK_PATTERN = withBoundaries('```([^`]+)```')
+const INLINE_CODE_PATTERN = withBoundaries('`(\\S(?:[^`\\n]*\\S)?)`')
+const BOLD_PATTERN = withBoundaries('\\*(\\S(?:[^*\\n]*\\S)?)\\*')
+const ITALIC_PATTERN = withBoundaries('_(\\S(?:[^_\\n]*\\S)?)_')
+const STRIKE_PATTERN = withBoundaries('~(\\S(?:[^~\\n]*\\S)?)~')
+
+// Characters that are stripped off the end of a matched URL because they are
+// Sentence punctuation that is always treated as trailing text, never part
+// of a URL (balanced closing parentheses are handled separately below).
+const URL_TRAILING_PUNCTUATION = new Set([
+ ',',
+ '.',
+ ';',
+ ':',
+ '!',
+ '?',
+ "'",
+ '"',
+ ']',
+ '}',
+])
+
+// WhatsApp formatting-marker characters. A trailing one of these is only
+// stripped from a URL when it pairs with a matching opening delimiter
+// immediately before the URL (e.g. the closing `*` in `*https://x.com*`),
+// so legitimate URL characters like the trailing `_` in `.../file_name_`
+// are preserved.
+const URL_TRAILING_MARKERS = new Set(['*', '_', '~', '`'])
+
+/**
+ * Splits a raw URL match into the actual URL and any trailing characters
+ * that aren't part of it. Closing parentheses are balance-checked so URLs
+ * such as `https://example.com/page_(v2)` keep their closing parenthesis.
+ */
+function splitTrailingPunctuation(
+ raw: string,
+ precedingChar: string | undefined,
+): {
+ url: string
+ trailing: string
+} {
+ let end = raw.length
+ while (end > 0) {
+ const char = raw[end - 1] as string
+ if (char === ')') {
+ const opens = (raw.slice(0, end).match(/\(/g) ?? []).length
+ const closes = (raw.slice(0, end).match(/\)/g) ?? []).length
+ if (closes <= opens) break
+ end--
+ continue
+ }
+ if (!URL_TRAILING_PUNCTUATION.has(char)) break
+ end--
+ }
+
+ if (end > 0) {
+ const char = raw[end - 1] as string
+ if (URL_TRAILING_MARKERS.has(char) && precedingChar === char) {
+ end--
+ }
+ }
+
+ return { url: raw.slice(0, end), trailing: raw.slice(end) }
+}
+
+/**
+ * Stores HTML fragments (links, code spans) behind unique placeholder
+ * tokens so that the markdown replacements that run afterwards don't touch
+ * them. Each store instance uses a random per-call nonce so that literal
+ * text in the message can never collide with a placeholder token.
+ */
+function createPlaceholderStore() {
+ const nonce = Math.random().toString(36).slice(2)
+ const open = `\uE000${nonce}:`
+ const close = `:${nonce}\uE000`
+ const store: string[] = []
+ const pattern = new RegExp(`${open}(\\d+)${close}`, 'g')
+
+ return {
+ protect(html: string): string {
+ store.push(html)
+ return `${open}${store.length - 1}${close}`
+ },
+ restore(text: string): string {
+ return text.replace(pattern, (_, idx: string) => store[Number(idx)] ?? '')
+ },
+ }
+}
+
+type PlaceholderStore = ReturnType${content}`),
+ )
+ .replace(INLINE_CODE_PATTERN, (_, content: string) =>
+ placeholders.protect(`${content}`),
+ )
+}
+
+/**
+ * Converts WhatsApp-style formatted text into sanitized HTML.
+ * Supported syntax (each marker pair must be surrounded by whitespace,
+ * punctuation, or the start/end of the string, and must not have internal
+ * leading/trailing whitespace, matching WhatsApp's own formatting rules):
+ * - *bold*
+ * - _italic_
+ * - ~strikethrough~
+ * - `code` / ```code block``` (code content is never re-formatted)
+ * - "> " quoted lines (the space after ">" is required)
+ * - raw URLs, turned into clickable links
+ */
+export function formatWhatsappText(text: string): string {
+ const escaped = escapeHtml(text ?? '')
+ const placeholders = createPlaceholderStore()
+
+ const withLinks = linkifyUrls(escaped, placeholders)
+
+ const withQuotes = withLinks
+ .split('\n')
+ .map((line) => {
+ const quoteMatch = line.match(/^> (.*)$/)
+ if (quoteMatch) {
+ return `${quoteMatch[1]}`
+ }
+ return line
+ })
+ .join('\n')
+
+ const withCode = extractCodeSpans(withQuotes, placeholders)
+
+ const formatted = withCode
+ .replace(BOLD_PATTERN, '$1')
+ .replace(ITALIC_PATTERN, '$1')
+ .replace(STRIKE_PATTERN, '- httpSMS is an - open source - application that converts your android phone into an SMS gateway so you - can send and receive SMS messages using a simple HTTP API. -
-- Start sending messages -
-- Install the mobile app on your android phone to start sending messages -
-- {{ $store.getters.getOwner | phoneCountry }} -
-
- Made With
-
- Your next bill is for ${{ plan.price }} on - {{ - new Date( - $store.getters.getUser.subscription_renews_at, - ).toLocaleDateString() - }} -
-- You are on the life time plan which costs - ${{ plan.price }} -
-- You will be downgraded to the FREE plan on - {{ - new Date( - $store.getters.getUser.subscription_ends_at, - ).toLocaleDateString() - }} -
-- {{ totalMessages }}/{{ plan.messagesPerMonth }} messages -
-- You will be downgraded to the free plan at the end - of the current billing period on - {{ - new Date( - $store.getters.getUser.subscription_renews_at, - ).toLocaleDateString() - }} -
-5,000 messages monthly
-5,000 messages monthly
-
- This is the summary of the sent messages and received messages in
- {{
- $store.getters.getBillingUsage.start_timestamp | billingPeriod
- }}.
-
Messages Sent
-Messages Received
-Total Cost
-- Summary of all the sent and received messages in the past 12 - months -
-- {{ postDate }} - • {{ readTime }} -
-
- You can now program your android phone to forward messages received on
- your phone to your server and trigger powerful automations with tools
- like Zapier and IFTTT. I created an open source application called
-
- Create an account on the httpSMS web application and copy your API key
- from the settings page.
-
- Install the
- httpSMS
- android app on your phone and sign in using your API KEY which you
- copied above. This app listens for SMS messages received on your
- android phone.
👉
- https://github.com/NdoleStudio/httpsms/releases/latest/download/HttpSms.apk
-
- Once the application has been installed, it will be listening for SMS
- messages received on the android phone. You can configure the
- application to sent this SMS message to your server URL using a
- webhook. You can configure this URL under the settings page in the
- httpSMS application
-
- Congratulations, you have successfully set up SMS forwarding from your - Android phone to a webhook! This powerful automation tool can help you - streamline your business workflow and save you time and effort. -
-- You can also trigger the httpSMS application to send an SMS a simple - API. You can find more information on the documentation page at - https://docs.httpsms.com -
-Until the next time✌️
-{{ authorName }}
- - {{ authorTwitter }} -- {{ post.description }} -
-{{ post.authorName }}
-
- {{ post.authorTwitter }}
-
- {{ postDate }} - • {{ readTime }} -
-- In an era dominated by social media, instant messaging apps, and - ever-evolving communication technologies, it's easy to overlook the - humble yet remarkably resilient Short Message Service (SMS). Since its - inception in the 1990s, SMS has stood the test of time, remaining one - of the most widely used and reliable means of mobile communication. -
-- Whether you're a business owner looking to optimize your communication - strategy, a developer seeking to integrate SMS functionality into your - applications, or simply intrigued by the enduring charm of SMS, this - article will explain how to setup your Android phone to send SMS - messages. -
-
- Create an account on
-
- ⬇️ Download and install - the httpSMS android app on your phone and sign in using your API KEY - which you copied above. This app listens for SMS messages received on - your android phone. -
-
- Now that you have setup your android phone correctly on httpSMS, you
- can write the python code below in a new file named
- send_sms.py. This code will send and SMS and after
- running the script via your Android phone to the recipient phone
- number specified in the payload.
-
api_key from step 1 and also
- use the correct to and from phone numbers in
- the payload variable.
-
-import requests
-import json
-
-api_key = "" # Get API Key from https://httpsms.com/settings
-
-url = 'https://api.httpsms.com/v1/messages/send'
-
-headers = {
- 'x-api-key': api_key,
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
-}
-
-payload = {
- "content": "This is a sample text message sent via python",
- "from": "+18005550199", # This is the phone number of your android phone */
- "to": "+18005550100" # This is the recipient phone number */
-}
-
-response = requests.post(url, headers=headers, data=json.dumps(payload))
-
-print(json.dumps(response.json(), indent=4))
-
-
-
- Run the code above with the command
- python send_sms.py and check the phone specified in the
- to field of the payload to verify that the
- message has been received successfully.
-
- Congratulations, you have successfully configured your android phone - to send SMS messages via python. You can now reuse this code to send - SMS messages from your python applications. -
-
- If you are also interested in forwarding incoming SMS from your
- android phone to your server, checkout our
-
Until the next time✌️
-{{ authorName }}
- - {{ authorTwitter }} -- Every 15 minutes, the httpSMS app on your Android phone sends a - heartbeat event to the httpsms API to show that it is alive. The - reason for this is because the Android operating system sometimes - kills an application to save battery - https://dontkillmyapp.com. -
-- If httpSMS doesn't get any heartbeat event in a 1-hour interval, - you will get an email notification about it so you can check if - there is an issue with your Android phone. -
-- The table below shows the last 100 heartbeat events received from - the httpSMS app on your Android phone. -
-- ⚡Trusted by 1,387+ happy users who have sent or received - more than 192,331+ messages -
-
-let apiKey = "Get API Key from https://httpsms.com/settings";
-
-fetch('https://api.httpsms.com/v1/messages/send', {
- method: 'POST',
- headers: {
- 'x-api-key': apiKey,
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- "content": "This is a sample text message",
- "from": "+18005550199",
- "to": "+18005550100"
- })
-})
-.then(res => res.json())
-.then((data) => console.log(data));
-
-
-
-<?php
-$apiKey = "Get API Key from https://httpsms.com/settings";
-
-$options = array(
- 'http' => array(
- 'method' => 'POST',
- 'content' => json_encode( [
- 'content' => 'This is a sample text message',
- 'from' => "+18005550199", // Put the correct phone number here
- 'to' => "+18005550100" // Put the correct phone number here
- ]),
- 'header'=> "Content-Type: application/json\r\n" .
- "Accept: application/json\r\n" .
- "x-api-key: $apiKey\r\n"
- )
-);
-
-$context = stream_context_create( $options );
-$result = file_get_contents( "https://api.httpsms.com/v1/messages/send", false, $context );
-
-echo $result;
-
-
-
-import requests
-import json
-
-api_key = "Get API Key from https://httpsms.com/settings"
-
-url = 'https://api.httpsms.com/v1/messages/send'
-
-headers = {
- 'x-api-key': api_key,
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
-}
-
-payload = {
- "content": "This is a sample text message",
- "from": "+18005550199",
- "to": "+18005550100"
-}
-
-response = requests.post(url, headers=headers, data=json.dumps(payload))
-
-print(json.dumps(response.json(), indent=4))
-
-
-
-import "github.com/NdoleStudio/httpsms-go"
-
-client := htpsms.New(htpsms.WithAPIKey(/* API Key from https://httpsms.com/settings */))
-
-client.Messages.Send(context.Background(), &httpsms.MessageSendParams{
- Content: "This is a sample text message",
- From: "+18005550199",
- To: "+18005550100",
-})
-
-
-
-var client = HttpClient.newHttpClient();
-var apiKey = "Get API Key from https://httpsms.com/settings";
-
-var payload = """
- {
- "content": "This is a sample text message",
- "from": "+18005550199",
- "to": "+18005550100"
- }
- """;
-
-var request = HttpRequest.newBuilder()
- .uri(URI.create("https://api.httpsms.com/v1/messages/send"))
- .header("accept", "application/json")
- .header("Content-Type", "application/json")
- .header("x-api-key", apiKey)
- .POST(HttpRequest.BodyPublishers.ofString(payload))
- .build();
-
-var response = client.send(request, HttpResponse.BodyHandlers.ofString());
-System.out.println(response.body());
-
-
-
-curl --location --request POST 'https://api.httpsms.com/v1/messages/send' \
---header 'x-api-key: Get API Key from https://httpsms.com/settings' \
---header 'Content-Type: application/json' \
---data-raw '{
- "from": "+18005550199",
- "to": "+18005550100",
- "content": "This is a sample text message"
-}'
-
-
-
-var client = new HttpClient();
-client.DefaultRequestHeaders.Add("x-api-key", ""/* Get API Key from https://httpsms.com/settings */);
-
-var response = await client.PostAsync(
- "https://api.httpsms.com/v1/messages/send",
- new StringContent(
- JsonSerializer.Serialize(new {
- from = "+18005550199",
- To = "+18005550100",
- Content = "This is a sample text message",
- }),
- Encoding.UTF8,
- "application/json"
- )
-);
-
-Console.WriteLine(await response.Content.ReadAsStringAsync());
-
-
- Monthly
-
- Yearly
-
- Try sending and receiving SMS on your hobby websites and - experiments. -
-- $0 -
-No credit card required
-
-
-
-
-
- Send and receive more SMS messages like a pro with advanced - features. -
-- $10/month -
-- $100/year -
-- or $100 per year -
-- or $8.33 per month -
-
-
-
-
-
- Send and receive up to 10,000 SMS messages like a power user. -
-- $20/month -
-- $200/year -
-- or $200 per year -
-- or $16.66 per month -
-
-
-
-
-
- Login to the HTTP SMS dashboard -
-
- Use your API Key in the x-api-key HTTP Header when
- sending requests to
- https://api.httpsms.com endpoints.
-
- Webhooks allow us to send events to your server for example when - the android phone receives an SMS message we can forward the - message to your server. -
-
- Send and receive SMS messages without leaving your discord server
- with the httpsms discord app using the
- /httpsms command.
-
- List of mobile phones which are registered for sending and - receiving SMS messages. -
-- Click the button below to add the httpSMS bot to your discord - server. You need to do this so we can have permission to send - and receive messages on your discord server. -
-Send and receive messages using our API
-