Skip to main content
pindo-sms can be used directly in Vue components or extracted into a reusable composable. This page covers both patterns, plus a Nuxt.js server route example.

Installation

npm install pindo-sms

Options API

Instantiate PindoSMS in the data function so each component instance gets its own client, or create it outside the component for a shared instance:
App.vue (Options API)
import { PindoSMS } from 'pindo-sms';

export default {
  name: 'App',
  data() {
    return {
      pindoSMS: new PindoSMS(import.meta.env.VITE_PINDO_API_TOKEN),
      status: '',
    };
  },
  methods: {
    async sendMessage() {
      this.status = 'Sending...';
      try {
        await this.pindoSMS.sendSMS({
          to: '+250781234567',
          text: 'Hello from Vue!',
          sender: 'MyApp',
        });
        this.status = 'SMS sent!';
      } catch (error) {
        console.error('Failed to send SMS:', error);
        this.status = 'Failed to send SMS.';
      }
    },
  },
};

Composition API

With the Composition API, create the client inside setup or at the module level:
App.vue (Composition API)
<script setup lang="ts">
import { ref } from 'vue';
import { PindoSMS, SMSPayload } from 'pindo-sms';

const pindo = new PindoSMS(import.meta.env.VITE_PINDO_API_TOKEN);
const status = ref('');

async function sendMessage() {
  status.value = 'Sending...';
  const payload: SMSPayload = {
    to: '+250781234567',
    text: 'Hello from Vue!',
    sender: 'MyApp',
  };
  try {
    await pindo.sendSMS(payload);
    status.value = 'SMS sent!';
  } catch (error) {
    console.error('Failed to send SMS:', error);
    status.value = 'Failed to send SMS.';
  }
}
</script>

<template>
  <button @click="sendMessage">Send SMS</button>
  <p v-if="status">{{ status }}</p>
</template>

Composable

For larger applications, extract the SMS logic into a composable so multiple components can share it without duplicating code:
composables/usePindo.ts
import { PindoSMS, SMSPayload } from 'pindo-sms';

const pindo = new PindoSMS(import.meta.env.VITE_PINDO_API_TOKEN);

export function usePindo() {
  async function sendSMS(to: string, text: string, sender: string): Promise<any> {
    const payload: SMSPayload = { to, text, sender };
    return pindo.sendSMS(payload);
  }

  async function sendBulkSMS(
    recipients: { phonenumber: string; name: string }[],
    text: string,
    sender: string,
  ): Promise<any> {
    return pindo.sendBulkSMS({ recipients, text, sender });
  }

  return { sendSMS, sendBulkSMS };
}
Import and call usePindo in any component:
components/NotificationButton.vue
<script setup lang="ts">
import { usePindo } from '@/composables/usePindo';

const { sendSMS } = usePindo();

async function notify() {
  await sendSMS('+250781234567', 'Your order is ready.', 'MyApp');
}
</script>

<template>
  <button @click="notify">Notify customer</button>
</template>

Environment variables

Vite (and therefore Vue CLI projects using Vite) exposes variables prefixed with VITE_ to the client bundle:
.env
VITE_PINDO_API_TOKEN=your_api_token_here
VITE_ variables are embedded in the client-side bundle and visible to anyone who inspects your JavaScript. Use this only for tokens that are acceptable to expose, or proxy SMS requests through a backend.

Nuxt.js server route

In a Nuxt 3 application, handle SMS sending in a server route so the token stays on the server:
1

Add the token to your environment

.env
PINDO_API_TOKEN=your_api_token_here
Nuxt 3 reads .env automatically. Access server-only variables via useRuntimeConfig() in server routes.
2

Configure runtimeConfig

nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    // Server-only — not exposed to the client
    pindoApiToken: process.env.PINDO_API_TOKEN,
  },
});
3

Create the server route

server/api/send-sms.post.ts
import { PindoSMS, SMSPayload } from 'pindo-sms';

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig();
  const pindo = new PindoSMS(config.pindoApiToken);

  const body = await readBody<SMSPayload>(event);
  const { to, text, sender } = body;

  if (!to || !text || !sender) {
    throw createError({ statusCode: 400, message: 'Missing required fields: to, text, sender' });
  }

  return pindo.sendSMS({ to, text, sender });
});
4

Call the route from a Vue component

pages/index.vue
<script setup lang="ts">
const status = ref('');

async function send() {
  status.value = 'Sending...';
  try {
    await $fetch('/api/send-sms', {
      method: 'POST',
      body: { to: '+250781234567', text: 'Hello from Nuxt!', sender: 'MyApp' },
    });
    status.value = 'SMS sent!';
  } catch {
    status.value = 'Failed to send SMS.';
  }
}
</script>

<template>
  <button @click="send">Send SMS</button>
  <p v-if="status">{{ status }}</p>
</template>
The Nuxt runtimeConfig.pindoApiToken field (without public.) is available only in server routes and Nitro handlers. It is never serialized into the client bundle.

Build docs developers (and LLMs) love