iMessage Inbox

Text an agent on iMessage. It replies in the same chat with context kept.

Private beta. Not available via the API today. client.bridges.provision() / bridges.create return 403 feature_disabled. iMessage is paused for self-serve API developers; the flow below is documentation for the platform preview and will change. For production API use, trigger agents by email or webhook.

Branding. The hosted flow runs on a shared m8tes number. Dedicated numbers exist today, one per app or per end-user, and we provision the line with you: email sales@m8tes.ai.

m8tes hosts iMessage. No server to run:

  1. Provision a hosted connection. You get the m8tes number to text and a short link code.
  2. Each person texts the link code once to that number to link their phone.
  3. They text the number; the message triggers a run; the agent replies in the same chat.
Python
from m8tes import M8tes

client = M8tes()

bridge = client.bridges.provision()   # idempotent: returns the same bridge if it exists
print(bridge.m8tes_handle)            # the number your team texts
print(bridge.link_code)               # each person texts this once to link their phone

# Once people have linked their phones, list or unlink them:
for h in client.bridges.list_handles(bridge.id):
    print(h.handle, h.verified_at)

Everyone shares one m8tes number, so inbound is routed to your account by the sender's verified handle (that is what the link code establishes). Rotate the code with client.bridges.regenerate_link_code(bridge.id); unlink a phone with client.bridges.remove_handle(bridge.id, handle_id). provision() raises a 503 if the platform's central server is not configured.

Hosted iMessage links a handle to your account; it does not carry an end-user user_id. For per-end-user channels in an embedded app, use email instead.

A dedicated number lifts that limit. It routes by number rather than by handle, so it can carry a user_id and give one app or one end-user its own line. Ask us to provision it.

Bind an Agent to a Chat

Give a specific agent one 1:1 chat by its chatGuid. Unbound inbound messages route to your account's Lead Mate instead.

Python
bot = client.agents.create(
    name="ops mate",
    instructions="Handle requests sent over iMessage. Keep replies short.",
    tools=["slack"],
    inbound_imessage_enabled=True,
    bridge_id=bridge.id,
    imessage_chat_guid="iMessage;-;+15551231234",        # a 1:1 chat (group chats are rejected)
    allowed_imessage_senders=["+15551231234"],            # required, fail-closed
)

Allowed Senders

allowed_imessage_senders takes phone or email handles (formatting and case are normalized). Without a listed sender, inbound messages are silently dropped, so only listed handles can spend a run. Same allowlist model as every inbox channel: see Allowed Senders.

Python
client.agents.update(bot.id, allowed_imessage_senders=["+15551231234", "you@icloud.com"])

Conversation Continuity

Incoming messageWhat happens
Previous run active within 72 hoursResumes the same run and context
More than 72 idle hoursStarts a new run; earlier history remains available on demand
Run still workingSends a “still working” acknowledgement; no parallel run

Only 1:1 chats are supported. Binding a group chat is rejected so an agent never broadcasts replies to a group.

Multi-Tenant iMessage

Self-hosted bridges support user_id scoping per chat, following the shared model in Multi-Tenant Sender Scoping:

Python
bot = client.agents.create(
    name="inbox bot",
    instructions="Handle this customer's iMessage requests",
    inbound_imessage_enabled=True,
    bridge_id=bridge.id,
    imessage_chat_guid="iMessage;-;+15557654321",
    allowed_imessage_senders=["+15557654321"],
    user_id="alice_123",
)
Advanced: bring your own BlueBubbles server

Run your own server (your own Apple ID and number) by registering a self-hosted bridge. A bridge is account-scoped and can serve many of your agents, each bound to a 1:1 chat.

Register a bridge

Python
from m8tes import M8tes

client = M8tes()

bridge = client.bridges.create(
    name="my mac",
    server_url="https://my-bridge.example.com",   # https, publicly reachable
    password="bluebubbles-api-password",           # stored encrypted, never returned
    owner_handle="+15551231234",                   # your own iMessage handle (optional)
)
print(bridge.webhook_secret)   # shown ONCE: set it as the BlueBubbles webhook secret now
print(bridge.connection_ok)    # True if m8tes reached your server and the password worked

Configure the BlueBubbles webhook to POST new-message events to https://api.m8tes.ai/api/v1/webhooks/inbound/imessage with header X-Webhook-Secret: <webhook_secret>.

owner_handle lets you text your Lead Mate the moment the bridge is registered, with no allowlist edit. It is honored only on the default-agent path; an agent bound to a specific chat still uses its own allowlist.

Check the connection

Python
result = client.bridges.test(bridge.id)   # pings the server; sends no message
print(result["ok"], result.get("detail"))

Run this if a bridge stops receiving or replying. It confirms the Mac is reachable and the password is still accepted.

Next: Email Inbox · Webhook Triggers · Memories & Documents

Was this page helpful?