Skip to main content

Overview

The iMessage resource enables you to send iMessages to iOS users with support for attachments, reactions (tapbacks), typing indicators, read receipts, and conversation history. It includes automatic SMS fallback for non-iMessage users.

Sending Messages

Send an iMessage to an iOS device.
const result = await contiguity.imessage.send({
  to: '+1234567890',
  message: 'Hello from iMessage!',
  from: '+0987654321'
});

console.log(result.message_id);

Parameters

to
string
required
The recipient’s phone number in E.164 format
message
string
required
The message content to send
from
string
The sender’s phone number. If not provided, a number will be automatically selected
attachments
string[]
Array of attachment URLs (images, videos, etc.)
fallback
object
SMS fallback configuration for non-iMessage users
fallback.when
array
required
Array of conditions triggering fallback: imessage_unsupported or imessage_fails
fallback.from
string
Optional different phone number to use for SMS fallback
fast_track
boolean
Enable fast-track delivery for time-sensitive messages

Returns

{
  message_id: string
}

Replying to Messages

Reply to an incoming iMessage webhook. This method automatically extracts to and from fields from the webhook event.
import { Contiguity } from 'contiguity';

const contiguity = new Contiguity('your-api-key');

// Inside your webhook handler
app.post('/webhook', async (req, res) => {
  const event = req.body;
  
  const result = await contiguity.imessage.reply(event, {
    message: 'Thanks for your iMessage!',
    attachments: ['https://example.com/response.jpg']
  });
  
  res.json({ success: true });
});

Parameters

event
WebhookEventBase
required
The incoming webhook event object containing data.to and data.from
params
Omit<ImessageSendParams, 'to' | 'from'>
required
Send parameters excluding to and from (automatically populated from event)

Typing Indicators

Show typing indicators to let users know you’re composing a response.
await contiguity.imessage.typing({
  to: '+1234567890',
  action: 'start',
  from: '+0987654321'
});

Parameters

to
string
required
The recipient’s phone number
action
'start' | 'stop'
required
Start or stop the typing indicator
from
string
The sender’s phone number

Reactions (Tapbacks)

Add or remove iMessage tapbacks (reactions) to messages.
const result = await contiguity.imessage.react('add', {
  to: '+1234567890',
  from: '+0987654321',
  message: 'Original message text',
  tapback: 'love'
});

Parameters

action
'add' | 'remove'
required
Whether to add or remove the reaction
params
object
required
Reaction parameters
params.to
string
required
The recipient’s phone number
params.from
string
required
The sender’s phone number
params.message
string
required
The original message text to react to
params.tapback
enum
required
The tapback type. One of: love, like, dislike, laugh, emphasize, question

Read Receipts

Mark messages as read.
await contiguity.imessage.read({
  to: '+1234567890',
  from: '+0987654321'
});

Parameters

to
string
required
The recipient’s phone number
from
string
required
The sender’s phone number

Conversation History

Retrieve message history between two phone numbers.
const history = await contiguity.imessage.history({
  to: '+1234567890',
  from: '+0987654321',
  limit: 50
});

Parameters

to
string
required
The recipient’s phone number
from
string
required
The sender’s phone number
limit
number
Maximum number of messages to retrieve (default: 20)

Getting a Single Message

Retrieve a specific message by its ID.
const message = await contiguity.imessage.get('msg_123456');

Parameters

id
string
required
The message ID to retrieve

Complete Conversation Example

import { Contiguity } from 'contiguity';

const contiguity = new Contiguity('your-api-key');

app.post('/webhook/imessage', async (req, res) => {
  const event = req.body;
  
  // Show typing indicator
  await contiguity.imessage.typing({
    to: event.data.from,
    from: event.data.to,
    action: 'start'
  });
  
  // Simulate processing time
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  // Stop typing indicator
  await contiguity.imessage.typing({
    to: event.data.from,
    from: event.data.to,
    action: 'stop'
  });
  
  // Send reply
  await contiguity.imessage.reply(event, {
    message: 'Thanks for your message!'
  });
  
  // Mark as read
  await contiguity.imessage.read({
    to: event.data.from,
    from: event.data.to
  });
  
  res.json({ success: true });
});

Fallback Strategy Example

// Try iMessage first, fall back to SMS if unavailable
const result = await contiguity.imessage.send({
  to: '+1234567890',
  message: 'This works on iMessage or SMS',
  from: '+0987654321',
  fallback: {
    when: ['imessage_unsupported', 'imessage_fails']
  }
});

// Use different number for SMS fallback
const result2 = await contiguity.imessage.send({
  to: '+1234567890',
  message: 'Premium message on iMessage, standard on SMS',
  from: '+0987654321', // iMessage number
  fallback: {
    when: ['imessage_unsupported'],
    from: '+1111111111' // Different SMS number
  }
});

Error Handling

try {
  const result = await contiguity.imessage.send({
    to: '+1234567890',
    message: 'Hello!'
  });
} catch (error) {
  if (error instanceof z.ZodError) {
    console.error('Validation error:', error.errors);
  } else {
    console.error('API error:', error);
  }
}
All methods validate input parameters using Zod schemas and throw validation errors for invalid input.

Best Practices

  • Always configure fallback for better delivery rates
  • Use typing indicators for natural conversation flow
  • Send read receipts to acknowledge received messages
  • Limit attachment sizes for faster delivery
  • Use fast_track only for truly urgent messages

Build docs developers (and LLMs) love