Build a demo tenant
This guide shows how to turn a user request into a demo tenant in your product.
For a standard Fictix customer, create the company in the Fictix Console and connect it with a project runtime key.
The programmatic control-plane flow below is for approved backend-to-backend
integrations. Configure the Fictix-supplied FICTIX_ADMIN_API_KEY as
X-Admin-Key server-side. The signed-in Console uses its own managed WorkOS
bearer session for Console actions; that session is not a customer credential to
copy or forward. Never use an email/password login, copy a browser session
token, or put the admin key in frontend code.
Goal
Given a user selection like:
Create a mid-market logistics company with QBO, Gusto, HubSpot, and Asana data.
Your system should:
- create a Fictix demo job
- wait for readiness
- fetch entity data
- map it into your product schema
- store lineage
- show the user a ready demo tenant
Recommended architecture
Browser
-> your backend
-> Fictix approved server-to-server demo-jobs API
-> your loader workers
-> your database
-> browser sees ready tenant
Do not call Fictix with management credentials directly from the browser.
Step 1: Build the create request
Map your UI form into the Fictix create payload:
{
"company": {
"name": "Acme Logistics",
"domain": "acme-logistics.example",
"industry": "Logistics",
"employee_count": 120,
"annual_revenue": 24000000,
"customer_accounts": 1500,
"selected_services": ["qbo", "gusto", "hubspot", "asana"]
},
"generation": {
"employees": 120,
"months_of_history": 24,
"quality_preset": "realistic"
},
"simulation": {
"seed": 42
}
}
Use .example domains for clearly synthetic companies.
ASC healthcare tenant
For a synthetic ambulatory surgery center, use company.industry rather than
company.archetype:
{
"company": {
"name": "Lakeside Surgery Center",
"domain": "lakeside-surgery.example",
"industry": "asc_surgical"
}
}
The resulting company adds synthetic clinical entities. It contains no real patient data; see Healthcare / ASC Data before loading or evaluating it.
Step 2: Create job with idempotency
Generate an idempotency key from your internal request id:
tenant-create-{tenant_request_id}
Then call:
/api/v1/demo-jobsPOST /api/v1/demo-jobs
Store:
- Fictix job id
- original request
- returned company metadata
- status
- links
- runtime ids
Step 3: Wait for readiness
Poll:
/api/v1/demo-jobs/{job_id}/statusGET /api/v1/demo-jobs/{job_id}/status
Treat status=ready as generation complete, then inspect quality:
/api/v1/demo-jobs/{job_id}/qualityGET /api/v1/demo-jobs/{job_id}/quality
Do not show a polished demo tenant if quality is unacceptable for your use case.
Step 4: Load core records
Recommended first load:
accountsbank_accountsitemscustomersvendorsemployeesinvoicescredit_memosbillscustomer_paymentsvendor_paymentsbank_transactionsjournal_entriesdealstaskspayroll_runs
For ASC companies, add operating_rooms, surgical_cases,
clinical_incidents, and dictation_scripts after the standard entities.
Fetch pages:
/api/v1/demo-jobs/{job_id}/entities/{entity}?limit=500&offset=0GET /api/v1/demo-jobs/{job_id}/entities/{entity}?limit=500&offset=0
Step 5: Store lineage
For each imported record, store:
fictix_job_idfictix_entityfictix_record_idfictix_loaded_atfictix_dataset_hash, if available
Lineage makes support, debugging, and replays possible.
Step 6: Expose tenant state to users
Show:
- company name
- generated systems
- loaded record counts
- generation quality
- last loaded timestamp
- any warnings
Avoid showing raw Fictix credentials in UI.
Failure handling
| Failure | User-facing behavior | Backend action |
|---|---|---|
| Auth failure | Route a normal customer to the Console; approved integrations should contact Fictix support | Verify exactly one approved management credential; do not retry with a project key, email/password, or browser session token |
| Generation budget exceeded | Ask user to reduce scale | Lower employees/months/services |
| Bundle too large | Continue loading by entity | Use entity pages |
| Quality failed | Show warning or block launch | Inspect quality endpoint |
| Loader partial failure | Show partial state | Resume from last entity/page |
Production checklist
- idempotency key is stable per user request
- no management or project key in browser
- generated data is marked synthetic in your product
- loader is resumable
- lineage is stored
- quality endpoint is checked
- counts are reconciled after load
- runtime API key is encrypted or not stored
