Submitting a Deal via Web Chat
Web chat is the browser-native way to submit a deal. Instead of dropping files in Slack, you start an intake conversation inside the Canvas web app, upload your documents, name the deal, and trigger generation — all without leaving the page. Progress streams back to your browser in real time, and when the memo is ready it opens directly in the Canvas editor.
Web chat and Slack intake feed the exact same analysis pipeline. The difference is only the front door: web chat is a guided, page-based wizard; Slack is conversational.
Starting a conversation
Section titled “Starting a conversation”Open the intake page in Canvas. A welcome message greets you (personalized if you have run deals before), and a new conversation is created for you. Each conversation has its own identity — internally it is keyed by a web- prefixed ID — which is what routes the finished memo back to your browser rather than to Slack.
The guided steps
Section titled “The guided steps”The intake page walks you through three steps, shown as a progress indicator (for example, 1/3 Upload documents → 2/3 Name your deal → 3/3 Ready to generate).
1. Upload documents
Section titled “1. Upload documents”Select your deal files. The accepted types are PDF (.pdf), Excel (.xlsx, .xls), and CSV (.csv) — the PDF offering memorandum and the Excel underwriting model being the two you will almost always provide. CoStar exports (PDFs) are auto-detected and welcome too. For what each input contributes to the memo, see What to Upload.
Two hard limits apply at upload:
- 50 MB maximum per file . The size is enforced while the file streams to disk, so an oversized file is rejected cleanly without ever being fully buffered.
- Up to 20 files per upload request .
As each file uploads it is validated — the filename is sanitized, the size is checked, and the content is verified against its extension. A file that is too large, has an invalid name, or is not a supported type is rejected with a clear message and an action to take (rename, shrink, or pick a supported format).
While files process, the page streams short status updates (“Validating…”, “Processing N documents…”, “Documents ready”). Memosa also takes a quick look at the first pages of your PDFs and your filenames to suggest a deal name and detect the deal type — so the next step is usually pre-filled.
2. Name the deal
Section titled “2. Name the deal”Confirm or edit the suggested deal name. The name is required (an empty name is rejected) and it is what creates the deal’s isolated namespace, so use the name you want on the finished memo. If your name does not match your firm’s naming convention, Canvas offers a gentle suggestion but does not block you.
3. Generate
Section titled “3. Generate”When both a document set and a deal name are present, the conversation reaches Ready to generate. Trigger generation and the analysis job is enqueued; the page immediately shows a queued event and then live progress as the worker picks up the job.
If you try to generate too early, the response tells you precisely what to do next — upload documents, set the deal name, wait for document processing to finish, or (if a run is already going) open the progress view instead of starting a duplicate.
Live progress (SSE)
Section titled “Live progress (SSE)”Once generation starts, the page subscribes to a Server-Sent Events (SSE) stream and renders progress as it happens — stage changes, percentage progress, status messages, and the final completion or error event.
- Heartbeats keep the connection alive. A heartbeat comment is sent on a regular cadence so the stream does not look dead during quiet stretches; the underlying SSE poll cycles about every 2 seconds , and the broader Canvas SSE heartbeat interval is 15 seconds .
- Reconnections do not rewind. Recent events are kept in a short history, and the stream honors the standard
Last-Event-IDheader, so if your connection blips and reconnects, you pick up where you left off instead of replaying stale progress. - A polling fallback exists. If SSE is unavailable, the page can poll the conversation’s status and still see the last-known progress. When a progress snapshot goes stale, the countdown dims rather than showing a misleadingly confident ETA.
When generation completes, the memo opens in the Canvas editor. (For what you can do there, see the editor overview.)
The active-conversation cap
Section titled “The active-conversation cap”Each user can have a capped number of active (non-terminal) conversations at once. The cap is 15 . The intake UI shows this as an “n of 15 active” indicator, reading the cap straight from the server so it never drifts.
The cap counts only live conversations:
- Finished conversations don’t count. Completed, errored, failed, and cancelled conversations are lazily evicted before the cap is enforced, so a long history of past deals never blocks a new one.
- Stale conversations are reclaimed. A conversation stuck mid-generation because a worker crashed is reclaimed after a generous timeout (the document-ingest phase after about 20 minutes; the memo-generation phase after a much longer window), and abandoned pre-generation conversations are cleared after roughly two days of inactivity.
If you genuinely hit the cap with 15 live conversations, Canvas tells you which ones are active so you can finish or close one. There is also a one-click “archive all” kill switch to free every active slot at once.
If something goes wrong: retry, cancel, recover
Section titled “If something goes wrong: retry, cancel, recover”Web chat is built to survive interruptions:
- Retry — after a failed generation, one action resets the conversation to ready and re-runs it. Your uploaded files and deal name are preserved.
- Cancel — stop an in-progress run. The worker is signaled to stop and the conversation moves to an error state you can retry from.
- Change documents — drop the current files and return to the upload step without losing the deal name or context you already entered.
- Recover — reopening the intake page rehydrates the full conversation (status, files, messages, and last progress) so you can resume exactly where you left off. If a conversation was reclaimed as a zombie while you were away, recovery surfaces that honestly with a “please retry” message.
Common situations
Section titled “Common situations”| You see | What it means |
|---|---|
| ”Maximum active conversations reached” | You have 15 live conversations. Finish, close, or archive one — the message lists which are active. |
| A file is rejected on upload | It exceeded 50 MB, had an invalid name, or is not a .pdf / .xlsx / .xls / .csv file. Fix and re-upload. |
| The ETA countdown dims | The progress stream went quiet; the page is being honest rather than showing a stale estimate. Generation is usually still running. |
| ”This conversation cannot be recovered” | The conversation was created without a complete owner identity. Start a new one. |
Sources
Section titled “Sources”src/canvas/services/web_intake_service.py— the web intake service: conversation creation, streaming file uploads, deal-name suggestion, SSE progress publishing, zombie reclamation, the active-conversation cap, and retry/cancel/recover/reset.src/canvas/services/web_intake_config.py— all intake limits and TTLs:max_file_size_bytes(50 MB),max_files_per_upload(20),max_active_conversations(15),allowed_extensions,pubsub_poll_timeout, and the staleness thresholds.src/canvas/routes/web_chat_routes.py— the 16 REST + SSE endpoints (create/list, upload, deal-name, prepare, generate, retry, cancel, reset-files, status, progress SSE, messages, recover, archive) and their error mapping.src/config/timeout_config.py—sse_heartbeat_interval_secs(15s).src/services/intake_coordinator.py—add_local_files()(the web upload path) and the readiness gating shared with Slack.src/types/canonical_status.py—ConversationStatusvalues and the terminal-status set used for cap eviction.