ARCA Request Access
ARCA

Build spec · beta

Request access: how to build it

The page at getarca.co/private asks what the creator wants, collects goal details then financial context, shows a preliminary answer, and asks for contact last. Live booking is Cal.com with an ARCA reference code (no figures in the URL). The Prototype tab is the working reference.

Beta decision. There is no listing link and no screenshot or photo upload. The creator types the details of what they want, and every number used in a calculation is typed or confirmed by them. No extraction, OCR or file storage is part of this build.

1. Principles

2. Screen map

IdScreenWrites to sessionEvents
goalScreen 1. Choose the goal, or choose the Jada pathgoal_typerequest_access_clicked, goal_flow_started, goal_selected, jada_chat_selected
detailsScreen 2. Goal details (per goal)goal_detailsgoal_details_completed
ctx0…ctx1Screen 3. Minimum financial context (1 or 2 steps)financial_inputsfinancial_context_started, financial_context_completed
thinkingTransition. Quiet "Looking at what you told me" text, minimum 1.2 spreliminary_result, result_statusnone
answerScreen 4. First answer (or fallback)nonepreliminary_answer_shown or answer_fallback_shown
contactScreen 6. Contact capturecontact, converted_atemail_submitted
successScreen 7. Success and next stepnonenone
jada, jadaDonePath B. Talk it through with Jada, scheduling, confirmationjadajada_chat_selected, jada_call_scheduled

3. Session model

A server-side session is created on the first goal selection and referenced by an httpOnly cookie (arca_sid, 24 hour sliding expiry). Save on every step with a debounced PATCH, so a refresh or a return visit resumes where the user left off.

intake_session {
  session_id            text pk            // "sess_" + random
  created_at, updated_at, last_step
  goal_type             enum               // see section 4
  goal_details          jsonb              // per goal, see prototype fields
  financial_inputs      jsonb              // integers in dollars, enums for ranges
  preliminary_result    jsonb null         // see section 5
  result_status         enum null          // user_reported_estimate | plaid_derived | verified
  contact               { first_name, email, phone? } null
  converted_at          timestamptz null   // set when email is captured
  jada                  { note?, slot?, booking_id? } null
  utm, referrer, user_agent_hash
}

4. Goal types

Enum: apartment, home, car, quit_job, savings, grow_business, custom. Changing goal after Back clears goal_details and financial_inputs.

GoalNeeded to calculateOptional
apartmentmonthly rent, monthly incomelocation, move-in, landlord requirement, income type, savings, credit range, housing cost, guarantor
homeprice, annual income, down payment availablelocation, timing, desired down payment, credit range, monthly debts, housing payment
carprice, annual incomemake, model, year, timing, cash or finance, down payment, credit range, debts
quit_jobtarget (months or amount), monthly spending, savings, monthly incometarget date
savingstarget (months or amount), monthly spending, savings, monthly incometiming
grow_businessamount needed, current cash, monthly revenuepurpose, timing, obligations
customnothing. Always returns the fallback answer in betafree text, income, savings

5. Calculation layer

Run on the server (POST /api/intake/sessions/:id/result) so formulas and constants can change without a front-end release. The prototype contains a client-side copy of the same rules so the flow can be tried end to end.

result {
  label            "Your apartment"
  headline         "You’re close."              // human answer, shown largest
  metric           "You make about 2.9× the monthly rent."
  explanation      string
  helping[]        string[]                      // only when we can name them
  holding_back[]   string[]
  next             "ARCA can help you …"
  calc             { formula, inputs, value, assumptions }   // never shown as the headline
  confidence       "estimate" | "none"
}
GoalRule used in the prototype (placeholders, finance to confirm)
apartmentratio = monthly income ÷ rent. At least 3.2 → "You’re there." 2.6 to 3.2 → "You’re close." Below 2.6 → "This is a stretch."
homedown payment needed = desired down payment, else 10% of price. Months to go = shortfall ÷ (20% of monthly income). Window = a 3 month range starting that many months from today. Price ÷ income above 4.5 reads as a stretch.
carPayment on the financed amount at 7% over 60 months. Payment ÷ monthly income at or under 10% → "This fits."
quit_job, savingsTarget = months × spending, or the stated amount. Months to go = shortfall ÷ (income − spending). If income does not cover spending → "Not at this pace."
grow_businessMonths to go = shortfall ÷ (15% of monthly revenue).

Status separation. Everything computed from this flow is stamped result_status = user_reported_estimate. Plaid-derived numbers become plaid_derived; numbers confirmed against tax or income documents become verified. A result may only be promoted to a stronger status when every input has that status. Never overwrite a self-reported value with a derived one silently: keep both, show the source.

6. Goal details input

7. Email capture and conversion

8. Jada scheduling

Three entry points open the same scheduling flow: goal ("Talk it through with Jada"), answer and contact ("Rather talk it through? Schedule time with Jada"), and success ("Schedule time with Jada"). The optional note ("Anything you want Jada to know?") is stored as jada.note.

9. Beta Slack handoff

On email_submitted (and on jada_call_scheduled when no email was captured earlier), post one message to the beta intake channel through the existing failsafe workflow. The Slack tab in the prototype renders this message from the live session.

BlockContent
Creatorname, email, phone if given
Goalgoal type, goal details
Financial contextincome, savings, credit range, expenses and debts, any other answer. Marked "self-reported"
ARCA preliminary answerheadline, metric, calculation inputs and assumptions
Missing informationunanswered fields plus standard gaps (connected accounts, tax documents, income history)
ActionsOpen user · Edit goal · Correct financial inputs · Add data · Recalculate · Schedule / follow up

Actions are Slack interactive buttons that call the internal API with the session_id. "Correct financial inputs" and "Recalculate" must write a new result with its own timestamp and keep the previous one.

10. Analytics

EventWhenProperties
request_access_clickedHomepage CTA clicksource (hero, closing), utm
goal_flow_startedFirst goal selectedsession_id
goal_selectedGoal chosengoal_type
goal_details_completedLeaving screen 2goal_type, fields_filled
financial_context_startedEntering first context stepgoal_type
financial_context_completedLeaving last context stepgoal_type, fields_filled
preliminary_answer_shownReal answer renderedgoal_type, headline, result_status
answer_fallback_shown"I need a little more context" renderedgoal_type, reason
email_submittedContact form submittedgoal_type, has_phone
jada_chat_selectedAny Jada entry point clickedsource (goal_select, answer, contact, success)
jada_call_scheduledBooking confirmedsource, had_session
flow_abandonedPage hidden or closed before successgoal_type, last_step, saw_answer

Primary funnel: visitors → reached a meaningful answer (preliminary_answer_shown) → chose to book or email the result (email_submitted or jada_call_scheduled after an answer). Email conversion by itself is not the headline metric. Fallback answers do not count as "reached an answer".

11. Failsafes

SituationBehavior
Anything optional is left blankSilent. Manual fields are always visible. No error banner.
Unusual goal"Something else" with free text. Always reaches the fallback answer and the Jada or follow-up options.
A needed number is missingContinue is never disabled. The answer screen shows "I need a little more context to answer this well." with Talk it through with Jada and Tell us where to send the follow-up.
Calculation errors or times out (6 s)Same fallback. Log answer_fallback_shown with the reason.
Session cookie lostStart a new session. Offer to resume if a recent session exists for the same browser.
Slack post failsRetry with backoff. The user still sees success. Alert internally if retries are exhausted.

12. Open questions