Open Support is a SwiftUI iPhone app for operating a WhatsApp Business support inbox without using Meta's WhatsApp Business app UI.
The app is a mobile operator client. It does not talk to Meta directly and it does not store WhatsApp API secrets on the device. You run your own backend, the backend receives Meta WhatsApp Cloud API webhooks, stores conversations, sends replies, registers APNs devices, and optionally generates AI suggestions.
- WhatsApp-style inbox and conversation views
- Operator login with bearer-token sessions
- Text replies, images, videos, documents, and voice notes
- Voice-note playback before and after sending
- Push notifications for inbound customer messages
- AI draft replies and suggested actions from your backend
- Thread statuses, labels, owner/profile attachment, and read state
- Typing/read indicator calls for the latest inbound WhatsApp message
- Xcode 16 or newer
- iOS 17 or newer
- An Apple Developer account if you want to install on real devices outside the simulator
- A backend implementing docs/backend-api.md
- A Meta WhatsApp Cloud API phone number and webhook receiver
- APNs credentials for your app bundle identifier
Clone the repository:
git clone https://github.com/jewprobablyknow/open-support-ios.git
cd open-support-ios
open OpenSupport.xcodeprojIn Xcode:
- Select the
Open Supporttarget. - Set your Apple development team.
- Change the bundle identifier from
com.example.opensupportto your own id, for examplecom.yourcompany.opensupport. - Set
SUPPORT_API_BASE_URLin Build Settings to your backend URL, for examplehttps://support-api.yourcompany.com. - Build and run on a simulator or a paired iPhone.
The app stores the operator bearer token in the iOS Keychain under the app bundle identifier.
This is the fastest path for testing:
- Connect your iPhone to your Mac.
- Open
OpenSupport.xcodeproj. - Select your iPhone as the run destination.
- Make sure the target has your Apple development team and bundle id.
- Press Run.
If iOS blocks launch, open iPhone Settings and trust the developer profile for your Apple ID or team.
For a small internal team, use one of:
- TestFlight
- Apple Business Manager / MDM
- Ad Hoc distribution with registered device UDIDs
- Enterprise distribution if your Apple account supports it
The repo does not ship a prebuilt .ipa, because every user needs their own bundle id, signing team, backend URL, and APNs topic.
Your backend is responsible for the production behavior:
- Create or connect a Meta WhatsApp Cloud API app and phone number.
- Configure Meta webhook delivery to your backend.
- Verify incoming webhook signatures.
- Store contacts, threads, messages, media references, labels, owners, profiles, and unread state.
- Send replies through Meta WhatsApp Cloud API.
- Stream or proxy WhatsApp media to authenticated operators.
- Register APNs device tokens from the app.
- Send APNs notifications when new inbound messages arrive.
- Optionally generate AI replies and suggested actions.
The exact API contract consumed by the app is documented in docs/backend-api.md.
The app calls:
POST /api/operator/support/auth/loginGET /api/operator/support/sessionPOST /api/operator/support/auth/logout
Your backend decides how operators are created and authenticated. A successful login returns an opaque bearer token and operator profile. The app sends that token as:
Authorization: Bearer <operator-token>The app posts APNs device tokens to:
POST /api/operator/support/push/devicesDELETE /api/operator/support/push/devices
Your backend should send APNs alerts when a WhatsApp webhook records a new inbound message. Use the configured app bundle id as the APNs topic.
For development builds, the app reports sandbox; for release builds, it reports production.
The app sends media through:
POST /api/operator/support/threads/:threadId/reply-with-media
Uploads are multipart form requests with:
body_text: optional caption/textattachments[]: one or more files
Incoming messages can include media.download_url. The app requests that URL with the operator bearer token, so the backend should authenticate and then stream or redirect the media.
The app can ask the backend for suggested replies and actions:
POST /api/operator/support/threads/:threadId/suggestDELETE /api/operator/support/threads/:threadId/suggestion
Suggestions are treated as drafts. The app does not auto-send AI responses.
You can compile the project from the command line:
xcodebuild \
-project OpenSupport.xcodeproj \
-scheme "Open Support" \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGNING_ALLOWED=NO \
build- Check
SUPPORT_API_BASE_URL. - Make sure the URL uses HTTPS for device installs.
- Confirm your backend has the endpoints listed in docs/backend-api.md.
- Check that CORS is not relevant here; this is a native app, not a browser.
- Confirm
POST /api/operator/support/auth/loginreturns the JSON shape in docs/backend-api.md. - Confirm the backend token is accepted by
GET /api/operator/support/session. - Delete the app from the device if you want to clear the stored Keychain token during testing.
- Confirm the app has notification permission.
- Confirm the backend receives the APNs device token.
- Confirm the APNs topic equals your bundle id.
- Use sandbox APNs for debug builds and production APNs for release builds.
- Confirm
download_urlis reachable by an authenticated operator. - Confirm the response has the correct content type.
- Do not expose raw Meta access tokens or public unauthenticated media URLs.
- Do not put Meta access tokens or API secrets in the iOS app.
- Keep Meta WhatsApp Cloud API credentials only on your backend.
- Authenticate operators before returning media download URLs.
- Treat AI-generated suggestions as drafts, not automatic replies.
MIT. See LICENSE.