A private, invite-only messaging API. Users can only join with an invite code. No passwords — authentication is done via email OTP. Messages are encrypted at rest.
Built with Ruby on Rails 8, PostgreSQL, Action Cable for real-time events, and Solid Queue for background jobs.
This is the easiest way to run the app locally. You only need Docker Desktop installed — no Ruby, no PostgreSQL, nothing else.
Download and install from docker.com. Open it and let it start before continuing.
git clone https://github.com/talkencrypted-maker/talkEncrypted.git
cd talkEncryptedCreate a file called .env in the project root with the master key (get this from the project owner):
RAILS_MASTER_KEY=your_master_key_here
docker-compose upThis will:
- Start a PostgreSQL database
- Create the database and run all migrations automatically
- Start the Solid Queue background job worker
- Start the Rails server
The API will be available at http://localhost:3000/api.
docker-compose downTo also delete the database volume (wipe all data):
docker-compose down -vIf you prefer to run without Docker, you will need:
- Ruby 4.0.3
- PostgreSQL 14+
- Bundler
bundle installbin/rails db:create db:migratebin/rails runner "load Rails.root.join('db/queue_schema.rb')"bin/rails serverbin/rails solid_queue:startThe API will be available at http://localhost:3000/api.
All endpoints (except auth) require:
Authorization: Bearer <token>
Content-Type: application/json
| Method | URL | Description |
|---|---|---|
| POST | /api/auth/otp/request |
Request OTP (invite code required for new users) |
| POST | /api/auth/otp/verify |
Verify OTP and get Bearer token |
| DELETE | /api/logout |
End session |
| GET | /api/me |
Get my profile |
| PATCH | /api/me |
Update display name / bio |
| GET | /api/users/search |
Search for users |
| GET | /api/conversations |
List my conversations |
| POST | /api/conversations |
Start a new conversation |
| GET | /api/conversations/:id |
Get conversation details |
| POST | /api/conversations/:id/read |
Mark conversation as read |
| GET | /api/conversations/:id/messages |
Load messages |
| POST | /api/conversations/:id/messages |
Send a message |
Connect with your Bearer token:
ws://localhost:3000/cable?token=<your_token>
Subscribe to a conversation:
{ "channel": "ConversationChannel", "conversation_id": 5 }Real-time events you will receive:
| Event type | When it fires |
|---|---|
message.created |
A new message is sent |
conversation.read |
Someone marks the conversation as read |
link_preview.updated |
A link preview finishes loading |
- Message bodies are encrypted at rest using Rails Active Record Encryption
- Session tokens are stored as SHA-256 digests — raw tokens are never saved
- OTP codes are stored as SHA-256 digests — raw codes are never saved
- Invite codes are stored as SHA-256 digests — raw codes are never saved
- WebSocket connections are authenticated via Bearer token