@jokoor/sdk
Version:
Jokoor SMS API SDK for JavaScript/TypeScript
447 lines (358 loc) • 12.3 kB
Markdown
# Jokoor SMS SDK for TypeScript/JavaScript
Official TypeScript/JavaScript SDK for the Jokoor SMS API. This SDK provides a simple and type-safe way to integrate Jokoor's SMS services into your applications.
## Features
- 🔐 **API Key Authentication** - Support for live modes only (SMS does not support test modes)
- 📱 **SMS Services** - Send individual or bulk SMS messages
- 📊 **Campaign Management** - Create and manage SMS campaigns
- 📝 **Template Management** - Create reusable message templates with variables
- 👥 **Contact Management** - Organize contacts and contact groups
- 🚀 **TypeScript Support** - Full type safety and IntelliSense
- ⚡ **Automatic Retries** - Built-in retry logic with exponential backoff
- 🛡️ **Result Pattern** - Type-safe `{data, error}` pattern for all API calls (no exceptions thrown)
## Installation
```bash
npm install @jokoor/sdk
# or
yarn add @jokoor/sdk
# or
pnpm add @jokoor/sdk
```
## Quick Start
```typescript
import { Jokoor } from '@jokoor/sdk';
const jokoor = new Jokoor('sk_live_your_api_key_here');
// Send an SMS - returns {data, error} instead of throwing
const { data: sms, error } = await jokoor.sms.send({
to: '+2207123456',
message: 'Hello from Jokoor!'
});
if (error) {
console.error('Failed to send SMS:', error);
} else {
console.log('SMS sent:', sms.id);
}
// Create a campaign
const { data: campaign, error: campaignError } = await jokoor.campaigns.create({
name: 'Summer Sale',
message: 'Get 20% off all items this weekend!',
contactGroupIds: ['grp_123']
});
if (campaignError) {
console.error('Failed to create campaign:', campaignError);
return;
}
// Send the campaign
const { error: sendError } = await jokoor.campaigns.send(campaign.id);
if (sendError) {
console.error('Failed to send campaign:', sendError);
} else {
console.log('Campaign sent successfully');
}
```
## Configuration
```typescript
const jokoor = new Jokoor('sk_live_your_api_key_here', {
baseURL: 'https://api.jokoor.com', // Optional (default)
timeout: 30000, // Optional, in milliseconds
maxRetries: 3, // Optional
debug: false // Optional, enables debug logging
});
```
## Template Variable System
### Overview
Jokoor's template system supports two types of variables for creating dynamic messages:
1. **Contact Fields** - Personalized per recipient
2. **Template Parameters** - Static values for all recipients
### Contact Fields (Dynamic Personalization)
Only these 3 fields are personalized per recipient:
- `{{first_name}}` or `{{firstName}}` - Contact's first name
- `{{last_name}}` or `{{lastName}}` - Contact's last name
- `{{email}}` - Contact's email address
### Template Parameters (Static Values)
All other variables remain the same for all recipients:
- Business data: `{{company_name}}`, `{{store_location}}`
- Promotional codes: `{{promo_code}}`, `{{discount}}`
- Dates/times: `{{event_date}}`, `{{expires_at}}`
- Any custom variable: `{{custom_field}}`
### How It Works
```typescript
// Template: "Hi {{first_name}}, enjoy {{discount}}% off with code {{promo_code}}!"
const campaign = await jokoor.campaigns.create({
name: 'Weekend Sale',
templateId: 'promo_template',
templateParams: {
first_name: 'Valued Customer', // Fallback if contact has no first_name
discount: '20', // Static - same for all recipients
promo_code: 'WEEKEND20' // Static - same for all recipients
},
contactGroupIds: ['all_customers']
});
// Results:
// John Doe → "Hi John, enjoy 20% off with code WEEKEND20!"
// Jane Smith → "Hi Jane, enjoy 20% off with code WEEKEND20!"
// Contact without name → "Hi Valued Customer, enjoy 20% off with code WEEKEND20!"
```
### Important Notes
- **Automatic Personalization**: The system automatically checks if phone numbers belong to contacts
- **Priority Rules**: Contact field values always override template parameters for contacts
- **Fallback Support**: Always provide fallback values for contact fields in templateParams
## Core API Usage
### SMS Operations
```typescript
// Send simple SMS
const sms = await jokoor.sms.send({
to: '+2207123456',
message: 'Your verification code is: 123456'
});
// Send scheduled SMS
const scheduledSMS = await jokoor.sms.send({
to: '+2207123456',
message: 'Reminder: Your appointment is tomorrow',
scheduledAt: '2024-01-20T10:00:00Z'
});
// Send SMS with template
const templatedSMS = await jokoor.sms.send({
to: '+2207123456',
templateId: 'tpl_welcome',
templateParams: {
firstName: 'John',
code: '123456'
}
});
// Get SMS status
const status = await jokoor.sms.get('sms_123');
// List SMS messages
const messages = await jokoor.sms.list({
limit: 50,
status: 'sent'
});
```
### Campaign Management
```typescript
// Create campaign with direct message
const campaign = await jokoor.campaigns.create({
name: 'Holiday Greetings',
message: 'Season\'s greetings from {{company_name}}!',
contactGroupIds: ['grp_customers'],
templateParams: {
company_name: 'Jokoor Inc.'
}
});
// Create campaign with template
const templateCampaign = await jokoor.campaigns.create({
name: 'Welcome Series',
templateId: 'tpl_welcome',
contactIds: ['contact_123', 'contact_456'],
templateParams: {
first_name: 'Valued Customer', // Fallback
discount_code: 'WELCOME10'
}
});
// Send campaign
await jokoor.campaigns.send(campaign.id);
// Get campaign statistics
const stats = await jokoor.campaigns.getStats(campaign.id);
console.log(`Sent: ${stats.data.details.totalSentMessages}`);
```
### Template Management
```typescript
// Create template
const templateResult = await jokoor.templates.create({
name: 'welcome_message',
body: 'Welcome {{firstName}}! Your code is {{code}}.'
});
if (templateResult.error) {
console.error('Failed to create template:', templateResult.error);
return;
}
// Update template
const updateResult = await jokoor.templates.update(templateResult.data.id, {
body: 'Hi {{first_name}}! Your code is {{code}}. Valid for {{validity}} minutes.'
});
if (updateResult.data) {
console.log('Template updated successfully');
}
// List templates
const listResult = await jokoor.templates.list();
if (listResult.data) {
console.log(`Found ${listResult.data.count} templates`);
}
```
### Contact Management
```typescript
// Create contact
const contact = await jokoor.contacts.create({
phoneNumber: '+2207123456',
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com'
});
// Update contact
await jokoor.contacts.update(contact.id, {
email: 'john.doe@example.com'
});
// Search contacts
const contacts = await jokoor.contacts.list({
search: 'john'
});
```
### Contact Groups
```typescript
// Create group
const group = await jokoor.contactGroups.create({
name: 'VIP Customers',
description: 'Premium tier customers'
});
// Add contacts to group
await jokoor.contactGroups.addContacts(group.id, [
'contact_123',
'contact_456'
]);
// Remove contacts from group
await jokoor.contactGroups.removeContacts(group.id, [
'contact_456'
]);
```
## Error Handling
The SDK uses a Result pattern - all methods return `{data, error}` instead of throwing exceptions. This makes error handling explicit and type-safe.
```typescript
// All API calls return a Result type - destructure for clean code
const { data, error } = await jokoor.sms.send({
to: 'invalid-number',
message: 'Test'
});
if (error) {
// Error is always a string
console.error('API Error:', error);
// Example errors:
// "Invalid phone number format"
// "Insufficient balance"
// "Rate limit exceeded"
// "Authentication failed"
// "Resource not found"
// "Service temporarily unavailable"
} else {
// TypeScript knows data is available here
console.log('SMS sent:', data.id);
}
// You can also rename while destructuring
const { data: sms, error: smsError } = await jokoor.sms.send({
to: '+2207123456',
message: 'Hello!'
});
```
### Result Type Utilities
The SDK exports helpful utilities for working with Results:
```typescript
import { isOk, isErr, unwrap, unwrapOr, map, chain } from '@jokoor/sdk';
// Check if successful
if (isOk(result)) {
console.log(result.data); // TypeScript knows data exists
}
// Check if error
if (isErr(result)) {
console.error(result.error); // TypeScript knows error exists
}
// Extract data or throw (for migration from try-catch)
try {
const data = unwrap(result);
} catch (e) {
console.error(e.message);
}
// Extract data or use default
const data = unwrapOr(result, { id: 'default' });
// Transform successful results
const idResult = map(result, sms => sms.id);
// Chain operations
const chainedResult = await chain(
await jokoor.sms.send({ to: '+123', message: 'Hi' }),
async (sms) => await jokoor.sms.get(sms.id)
);
```
### Common Error Messages
- **Authentication**: "Authentication failed", "Invalid API key"
- **Validation**: "Invalid phone number format", "Message body is required"
- **Resources**: "Resource not found", "Contact group not found"
- **Limits**: "Rate limit exceeded", "Insufficient balance"
- **Network**: "Unable to connect to API server", "Request timed out"
- **Server**: "Internal server error", "Service temporarily unavailable"
## TypeScript Support
Full type definitions for all methods and responses:
```typescript
import {
Jokoor,
JokoorConfig,
Result,
// Request Types
SMSSendParams,
CampaignCreateParams,
ContactCreateParams,
TemplateCreateParams,
// Response Types
SMSResponse,
CampaignResponse,
ContactResponse,
TemplateResponse,
// Utility Types
PaginatedResponse,
CampaignStats
} from '@jokoor/sdk';
```
## API Reference
### SMS (`jokoor.sms`)
- `send(params)` - Send an SMS message
- `get(id)` - Get SMS details
- `list(options?)` - List SMS messages
- `resend(id)` - Resend failed SMS
- `resendBatch(ids)` - Resend multiple failed messages
- `sendDraft(id, scheduledAt?)` - Send draft SMS
### Campaigns (`jokoor.campaigns`)
- `create(params)` - Create SMS campaign
- `get(id)` - Get campaign details
- `update(id, params)` - Update campaign
- `delete(id)` - Delete campaign
- `list(options?)` - List campaigns
- `send(id)` - Send campaign
- `getStats(id)` - Get campaign statistics
- `getMessages(id, options?)` - Get campaign messages
- `resendFailed(id)` - Resend failed messages
### Templates (`jokoor.templates`)
- `create(params)` - Create SMS template
- `get(id)` - Get template details
- `update(id, params)` - Update template
- `delete(id)` - Delete template
- `list(options?)` - List templates
### Contacts (`jokoor.contacts`)
- `create(params)` - Create contact
- `get(id)` - Get contact details
- `update(id, params)` - Update contact
- `delete(id)` - Delete contact
- `list(options?)` - List contacts
### Contact Groups (`jokoor.contactGroups`)
- `create(params)` - Create contact group
- `get(id)` - Get group details
- `update(id, params)` - Update group
- `delete(id)` - Delete group
- `list(options?)` - List groups
- `addContacts(id, contactIds)` - Add contacts to group
- `removeContacts(id, contactIds)` - Remove contacts from group
## Best Practices
1. **API Key Security**: Never expose your secret API key in client-side code
2. **Template Variables**: Always provide fallback values for contact fields
3. **Error Handling**: Wrap API calls in try-catch blocks
4. **Bulk Operations**: Use campaigns for sending to multiple recipients
5. **Contact Organization**: Use groups for better campaign targeting
6. **Rate Limiting**: Implement appropriate backoff strategies
## Documentation
For comprehensive guides and examples:
- 📚 [Full SDK Documentation](./docs/README.md)
- 📖 [Template Variable Guide](./docs/guides/templates/variable-rules.md)
- 🚀 [Quick Start Guide](./docs/getting-started/quick-start.md)
- 💡 [SMS Best Practices](./docs/guides/sms/sending-sms.md)
- 🎯 [Campaign Examples](./docs/guides/campaigns/creating.md)
## Support
- 📧 Email: hello@jokoor.com
- 📚 REST API Documentation: https://developers.jokoor.com
- 🐛 Issues: https://github.com/jokoor/sdk-typescript/issues
## License
MIT License - see LICENSE file for details