326 lines
7.5 KiB
Markdown
326 lines
7.5 KiB
Markdown
# textme-unofficial-api
|
|
|
|
> ⚠️ **UNOFFICIAL API** - This library is not affiliated with, endorsed by, or connected to TextMe Inc. in any way. Use at your own risk. This library may break at any time if TextMe changes their internal APIs.
|
|
|
|
An unofficial TypeScript/JavaScript client for the TextMe messaging service. Provides authentication, REST API access, and realtime WebSocket support.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
npm install textme-unofficial-api
|
|
```
|
|
|
|
## Requirements
|
|
|
|
- Node.js >= 18.0.0
|
|
- A TextMe account
|
|
|
|
## Quick Start
|
|
|
|
```typescript
|
|
import { TextMeClient } from 'textme-unofficial-api';
|
|
|
|
const client = new TextMeClient({
|
|
credentials: {
|
|
email: 'your-email@example.com',
|
|
password: 'your-password'
|
|
}
|
|
});
|
|
|
|
// Connect and authenticate
|
|
await client.connect();
|
|
|
|
// Listen for incoming messages
|
|
client.on('message.received', (event) => {
|
|
console.log('New message from:', event.message.senderPhoneNumber);
|
|
console.log('Content:', event.message.content.text);
|
|
});
|
|
|
|
// Send a message
|
|
await client.sendMessage({
|
|
recipientPhoneNumber: '+1234567890',
|
|
senderPhoneNumber: '+0987654321', // Your TextMe number
|
|
text: 'Hello from TextMe!'
|
|
});
|
|
|
|
// Get conversations
|
|
const conversations = await client.getConversations({ limit: 20 });
|
|
console.log(`You have ${conversations.data.length} conversations`);
|
|
|
|
// Disconnect when done
|
|
await client.disconnect();
|
|
```
|
|
|
|
## API Reference
|
|
|
|
### TextMeClient
|
|
|
|
The unified client that combines all functionality.
|
|
|
|
#### Constructor Options
|
|
|
|
```typescript
|
|
interface TextMeClientOptions {
|
|
// Authentication (provide one)
|
|
credentials?: { email: string; password: string };
|
|
tokens?: AuthTokens;
|
|
|
|
// Configuration
|
|
baseUrl?: string; // Custom API base URL
|
|
wsUrl?: string; // Custom WebSocket URL
|
|
timeout?: number; // Request timeout (ms)
|
|
debug?: boolean; // Enable debug logging
|
|
|
|
// Reconnection
|
|
autoReconnect?: boolean; // Auto-reconnect on disconnect
|
|
maxReconnectAttempts?: number; // Max reconnection attempts
|
|
reconnectDelay?: number; // Delay between attempts (ms)
|
|
}
|
|
```
|
|
|
|
#### Connection Methods
|
|
|
|
```typescript
|
|
// Connect and authenticate
|
|
await client.connect(): Promise<AuthSession>
|
|
|
|
// Disconnect from services
|
|
await client.disconnect(): Promise<void>
|
|
|
|
// Check connection status
|
|
client.isConnected(): boolean
|
|
```
|
|
|
|
#### Authentication Methods
|
|
|
|
```typescript
|
|
// Login with credentials
|
|
await client.login(credentials): Promise<AuthSession>
|
|
|
|
// Refresh tokens
|
|
await client.refreshTokens(): Promise<AuthTokens>
|
|
|
|
// Get current user info
|
|
await client.getCurrentUser(): Promise<User>
|
|
```
|
|
|
|
#### Messaging Methods
|
|
|
|
```typescript
|
|
// Send a message
|
|
await client.sendMessage({
|
|
recipientPhoneNumber: string,
|
|
senderPhoneNumber: string,
|
|
text?: string,
|
|
mediaUrls?: string[]
|
|
}): Promise<SendMessageResponse>
|
|
|
|
// Get conversations
|
|
await client.getConversations({
|
|
limit?: number,
|
|
offset?: number,
|
|
before?: string,
|
|
after?: string
|
|
}): Promise<PaginatedResponse<Conversation>>
|
|
|
|
// Get messages in a conversation
|
|
await client.getMessages({
|
|
conversationId: string,
|
|
limit?: number,
|
|
before?: string,
|
|
after?: string
|
|
}): Promise<PaginatedResponse<Message>>
|
|
|
|
// Mark messages as read
|
|
await client.markAsRead(conversationId: string, messageIds?: string[]): Promise<void>
|
|
|
|
// Delete a message
|
|
await client.deleteMessage(messageId: string): Promise<void>
|
|
```
|
|
|
|
#### Realtime Events
|
|
|
|
```typescript
|
|
// Subscribe to events
|
|
client.on('message.received', (event) => {
|
|
console.log(event.message);
|
|
});
|
|
|
|
client.on('message.status', (event) => {
|
|
console.log(`Message ${event.messageId} is now ${event.status}`);
|
|
});
|
|
|
|
client.on('typing.start', (event) => {
|
|
console.log(`Someone is typing in ${event.conversationId}`);
|
|
});
|
|
|
|
client.on('connection.close', (event) => {
|
|
console.log('Disconnected');
|
|
});
|
|
|
|
// Unsubscribe
|
|
client.off('message.received', handler);
|
|
|
|
// Send typing indicator
|
|
client.sendTyping(conversationId, true); // Started typing
|
|
client.sendTyping(conversationId, false); // Stopped typing
|
|
```
|
|
|
|
### Individual Modules
|
|
|
|
For advanced use cases, you can use the modules directly:
|
|
|
|
```typescript
|
|
import { TextMeAuth, TextMeAPI, TextMeRealtime } from 'textme-unofficial-api';
|
|
|
|
// Authentication only
|
|
const auth = new TextMeAuth({ debug: true });
|
|
const session = await auth.login({ email, password });
|
|
|
|
// API only
|
|
const api = new TextMeAPI();
|
|
api.setTokens(session.tokens);
|
|
const conversations = await api.getConversations();
|
|
|
|
// Realtime only
|
|
const realtime = new TextMeRealtime({ autoReconnect: true });
|
|
await realtime.connect(session.tokens);
|
|
realtime.on('message.received', console.log);
|
|
```
|
|
|
|
## Types
|
|
|
|
### User
|
|
|
|
```typescript
|
|
interface User {
|
|
id: string;
|
|
email: string;
|
|
displayName: string;
|
|
avatarUrl?: string;
|
|
phoneNumbers: PhoneNumber[];
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
```
|
|
|
|
### PhoneNumber
|
|
|
|
```typescript
|
|
interface PhoneNumber {
|
|
id: string;
|
|
number: string;
|
|
countryCode: string;
|
|
type: 'mobile' | 'landline' | 'voip' | 'unknown';
|
|
isPrimary: boolean;
|
|
isVerified: boolean;
|
|
capabilities: {
|
|
sms: boolean;
|
|
mms: boolean;
|
|
voice: boolean;
|
|
};
|
|
}
|
|
```
|
|
|
|
### Conversation
|
|
|
|
```typescript
|
|
interface Conversation {
|
|
id: string;
|
|
type: 'direct' | 'group';
|
|
participants: Participant[];
|
|
lastMessage?: Message;
|
|
unreadCount: number;
|
|
isPinned: boolean;
|
|
isMuted: boolean;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
```
|
|
|
|
### Message
|
|
|
|
```typescript
|
|
interface Message {
|
|
id: string;
|
|
conversationId: string;
|
|
senderId: string;
|
|
senderPhoneNumber: string;
|
|
recipientPhoneNumber: string;
|
|
content: {
|
|
type: 'text' | 'media' | 'mixed';
|
|
text?: string;
|
|
media?: MediaAttachment[];
|
|
};
|
|
status: 'pending' | 'sent' | 'delivered' | 'read' | 'failed';
|
|
direction: 'inbound' | 'outbound';
|
|
timestamp: string;
|
|
readAt?: string;
|
|
deliveredAt?: string;
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
```typescript
|
|
import { TextMeError, AuthenticationError, RateLimitError } from 'textme-unofficial-api';
|
|
|
|
try {
|
|
await client.connect();
|
|
} catch (error) {
|
|
if (error instanceof AuthenticationError) {
|
|
console.error('Invalid credentials');
|
|
} else if (error instanceof RateLimitError) {
|
|
console.error(`Rate limited. Retry after ${error.retryAfter}ms`);
|
|
} else if (error instanceof TextMeError) {
|
|
console.error(`API error: ${error.code} - ${error.message}`);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Token Persistence
|
|
|
|
To avoid logging in every time, save and restore tokens:
|
|
|
|
```typescript
|
|
import { TextMeClient } from 'textme-unofficial-api';
|
|
import fs from 'fs/promises';
|
|
|
|
// First time: login and save tokens
|
|
const client = new TextMeClient({
|
|
credentials: { email, password }
|
|
});
|
|
const session = await client.connect();
|
|
|
|
await fs.writeFile('tokens.json', JSON.stringify(session.tokens));
|
|
|
|
// Later: restore from saved tokens
|
|
const savedTokens = JSON.parse(await fs.readFile('tokens.json', 'utf-8'));
|
|
|
|
const client2 = new TextMeClient({
|
|
tokens: savedTokens
|
|
});
|
|
await client2.connect();
|
|
```
|
|
|
|
## ⚠️ Disclaimer
|
|
|
|
This is an **unofficial, reverse-engineered API client**. By using this library, you acknowledge:
|
|
|
|
1. **No Affiliation**: This project is not affiliated with TextMe Inc.
|
|
2. **Terms of Service**: Using this library may violate TextMe's Terms of Service
|
|
3. **No Warranty**: This library is provided "as is" without warranty of any kind
|
|
4. **Breakage Risk**: TextMe may change their internal APIs at any time, breaking this library
|
|
5. **Account Risk**: Your TextMe account could be suspended for using unofficial clients
|
|
6. **Legal Risk**: You are responsible for how you use this library
|
|
|
|
**Use responsibly and at your own risk.**
|
|
|
|
## License
|
|
|
|
MIT
|
|
|
|
---
|
|
|
|
*This library was created for educational purposes. Please respect TextMe's services and their users.*
|