PlaceRail documentation

A complete reference to the platform: how a split placement travels the rail, what every module does, and the technical detail behind consent, escrow, evidence and delivery.

What PlaceRail is

PlaceRail is deal infrastructure for split-fee recruiting: two recruiters — one holding the candidate (the exporter), one holding the client mandate (the importer) — transact on a shared rail that makes consent, identity, money and evidence verifiable instead of relational.

  • Candidate-first representation: nothing moves without a signed, scoped, timestamped Right to Represent (RTR).
  • Double-blind by default: listings, mandates and deal-room chat stay masked until both parties execute a split agreement.
  • Escrow-shaped economics: fee splits, guarantee periods, holdbacks and clawbacks are encoded at agreement time, not argued afterwards.
  • Tamper-evident record: every material action lands in an append-only, hash-chained event log that can be exported, signed and independently verified.
  • Dispute-to-arbitration path: evidence with per-item visibility windows, response deadlines, and locked arbitrator decisions.

Status: escrow, payouts and billing currently run as a demonstration rail. Ledger states, timelines and documents are real and auditable; no funds move until a payment provider and a licensed escrow agent are connected.

The deal lifecycle end to end

StageWhat happensWhere in the app
1. Candidate intakeCandidate record created by the owning recruiter; PII is owner-scoped./candidates
2. RepresentationRTR issued with scope, excluded companies and expiry; candidate signs via a tokenised link with a five-step guided flow./rtrs, /sign/:token
3. Blind listingA masked candidate listing (function, seniority, comp band, badges) is published from an active RTR./listings
4. MandateImporter publishes a masked job order: client descriptor, fee %, guarantee days, must-haves./job-orders
5. DiscoveryBlind feeds scored 0–100 against your own book, with saved searches and counterparty trust signals./network
6. Deal roomMasked chat, split negotiation, dual signature, execution./deals/:id
7. RevealOn execution, both identities reveal simultaneously and the reveal is logged.Deal room
8. PlacementStart date, guarantee window, fall-off tracking.Deal room · Placement panel
9. Escrow & payoutFunding, inspection window, release conditions, per-recruiter net payouts.Deal room · Payout schedule
10. SettlementSplit remittance statement plus downloadable invoices for both parties.Deal room · Remittance
11. ExceptionsDisputes, clawbacks, non-circumvention flags, arbitration.Deal room, /arbitration
12. EvidenceSigned PDF/CSV/ZIP exports, webhook delivery, independent verification./compliance, /verify

Right to Represent (RTR)

The RTR is the consent primitive. It is candidate-signed, scoped and time-bound, and the first signed RTR for a candidate wins in a conflict.

  • Scope: named client or client class, geography, role family, and an explicit excluded-companies list.
  • Expiry and revocation: every grant carries an expiry; candidates can revoke, and revocation is timestamped.
  • Guided signing: recruiter identification, scope review, expiry/revocation explanation, reveal-log acknowledgement, then signature.
  • Reveal log: the candidate sees, before signing, who can learn their identity and under what condition.
  • Conflict detection: rtr_conflict_count() matches on normalised candidate email across active, unexpired, unrevoked grants held by other recruiters.
  • Candidate portal: a tokenised, no-login portal where the candidate can review grants and status.

Double-blind listings, mandates and matching

  • Listings publish job function, seniority, market, relocation willingness, comp band (verified or claimed), asking split and badges — never names or employers.
  • Job orders publish a client descriptor, market, comp band, fee %, guarantee days and must-haves — never the client name.
  • Match scoring (0–100): function/title alignment 35, comp-band overlap 25, geography 15 (8 when relocation covers a mismatch), must-have coverage 15, seniority signal 10. Bands: strong ≥75, possible ≥45, otherwise weak.
  • Each score returns human-readable reasons and gaps so you can judge the number, not just trust it.
  • Saved searches persist keyword, market, comp floor and minimum split, scoped per user.
  • Trust signals show masked counterparty initials, tier, niche tags and reputation band before any identity is known.

Deal rooms, split agreements and reveal

A deal room is the shared workspace for one exporter/importer pair. It moves through six phases with an explicit next action at every point: masked chat → drafting → dual signing → escrow hold → guarantee → release.

  • Masked chat: counterparties are labelled by initials and tier until execution.
  • Split negotiation: offer/counter-offer on split %, fee basis, guarantee days and non-circumvention months, with a full offer history.
  • Dual signing: the agreement executes only when both parties sign; execution is what triggers identity reveal.
  • Simultaneous reveal: neither side learns the other first, and the reveal event is written to the deal's hash chain.
  • Encoded protections: non-circumvention window, guarantee/fall-off terms and clawback conditions are stored on the agreement, not in prose.

Escrow, guarantee and payout schedule

  • Escrow states: pending, in_progress, held, frozen, releasable, released, reversed.
  • Inspection window: derived from the placement start date and the agreement's guarantee days, with progress, days remaining and a paused-clock indicator.
  • Holdback: a portion of the split is retained through the guarantee period against fall-off risk.
  • Dispute freeze: an open dispute freezes advancement and pauses the inspection clock; the panel states this explicitly on both sides.
  • Release conditions: a checklist (placement recorded, guarantee elapsed, no open dispute, payee onboarding complete) gates authorisation.
  • Milestone timeline: candidate start → client payment → escrow funding → inspection close → release authorisation → settlement, with expected pay dates and per-recruiter net amounts.

Fees, remittance, invoices, payee onboarding and billing

  • Split remittance statement per placement: gross fee, split apportionment, platform deduction, holdback, net payable per party, with masked counterparty labels until reveal.
  • Invoice PDFs: party-specific invoices generated for both recruiters, numbered and dated, downloadable from the deal room.
  • Payee onboarding (W-9): legal and business identity, tax classification, TIN type and last four digits only, address, exemption and backup-withholding flags, certification metadata and form status. Full TINs are never persisted.
  • Billing: subscription tier, platform-fee invoices, open vs paid balances.
  • Desk analytics: open deals, pipeline fee value, earned fees, platform fees, outstanding balance, active listings and mandates.
  • Reputation scorecard: completion rate, fall-off rate, dispute rate and average days to close, folded into a 0–100 score with building/silver/gold/platinum bands.

Disputes, clawbacks, non-circumvention and arbitration

  • Dispute workflow: raise, attach evidence, counterparty response deadline (5 days) with countdown, resolution or escalation.
  • Evidence visibility: each item is Private, Shared, or Release-on-resolution — enforced in the database, not just the UI, and every visibility change is logged.
  • Clawback requests: tied to fall-off and guarantee terms, and linked to the escrow freeze state.
  • Non-circumvention detection: flags when the same candidate (matched on normalised email) appears at the same client on another revealed deal or placement inside the agreement's restricted window; both affected desks are notified. Actions: acknowledge, clear, escalate.
  • Arbitration: disputes route to an assigned arbitrator with auditable, scoped evidence access. Decisions are append-only — once issued they cannot be edited or deleted.
  • Notifications: dispute stage changes, evidence received, deadlines and integrity alerts, delivered in-app with a searchable inbox.

Audit log, hash chain and integrity monitoring

Every material action writes a deal_events row. Rows are append-only (update and delete raise) and chained: each row stores the previous row's hash, so any retro-edit breaks the chain from that point on.

event_hash = sha256(
  prev_hash | deal_id | rtr_id | dispute_id | actor_id |
  kind | detail | created_at
)
prev_hash of the first event in a chain = "genesis"
  • verify_deal_event_chain(deal_id): recomputes the whole chain for one deal and returns total, verified, first_broken_at.
  • sweep_event_chains(): platform-wide sweep across every deal chain.
  • Scheduled checks run hourly and write to integrity_checks (itself append-only); mismatches raise notifications and surface on the compliance dashboard.
  • The integrity monitor shows last-verified time, event counts and any first-broken timestamp per deal.

Exports: signed PDFs, CSV, ZIP bundles and verification

  • Deal audit PDF: deal summary, agreement terms, escrow detail, full event log and dispute trail, paginated A4.
  • Single-dispute PDF: one dispute's trail plus evidence metadata, optionally redacted to the viewer's permissions and the chosen visibility window.
  • Document seal: every export carries an HMAC-SHA256 seal and a verifiable digest printed in the footer.
  • Event-log CSV: sequence, timestamp, actor label, kind, detail, prev_hash and event_hash — for compliance ingestion and reconciliation. Filterable by dispute and by an eventsFrom/eventsTo datetime range.
  • ZIP bundle: the sealed PDF + the CSV + manifest.json carrying export timestamp and per-file digests.
  • Export log: every generation and delivery is recorded in audit_exports, with delivery outcome and retry state.
  • Public verification page at /verify: upload the CSV to re-check prev_hash/event_hash linkage, and check a PDF digest against its recorded seal — no login required.

Compliance webhooks — full technical spec

Export bundles can be pushed to one or more compliance endpoints. Delivery is HTTPS-only, signed, idempotent and retried, and every attempt is recorded with the exact scheme used so it can be reproduced byte for byte.

SettingOptionsNotes
Algorithmsha256 · sha384 · sha512HMAC over the signed message; per endpoint. Document seals remain HMAC-SHA256.
Encodinghex · base64Applies to the signature value.
Signature headerconfigurable nameDefault carries the active-key signature.
Timestamp headeroptional, configurable nameSent alongside the signature.
Timestamp formatunix seconds · unix millis · ISO 8601Used identically in the header and in the signed message.
Signed payload shapebody, or timestamp + bodyRecorded per attempt so verification is unambiguous.
IdempotencyIdempotency-Key headerDeterministic per export+endpoint; successful deliveries are not repeated.
Secret rotationper endpoint, grace up to 7 daysDuring grace, a previous-key signature is sent in a second header; secrets are shown once.
Retriesup to 6 attempts, exponential backoff (~3h)Scheduled worker; final status lands in the export log.
Fan-outmultiple endpointsIndependent outcomes and retry state per endpoint.

Header names keep their legacy X-Splitrail-* / x-splitrail-* spelling from before the PlaceRail rebrand. Existing signature-verification integrations keep working unchanged; the names are stable wire format, not branding.

Verifying a delivery on your side

message = timestamp_included
  ? `${timestamp}.${rawBody}`
  : rawBody

expected = HMAC(algorithm, endpointSecret, message)
           .digest(encoding)   // hex or base64

// constant-time compare against the signature header.
// during a rotation grace period, also accept the
// previous-key signature header.
  • Test/preview: send a sample signed payload and see HTTP status, latency, response headers and body preview — without writing an audit-trail entry.
  • Copy cURL: reproduce the exact signed request, including headers, timestamp and body.
  • Delivery timeline: per-attempt status, latency, HTTP code, response body hash and the stored signing scheme (algorithm, encoding, header names, timestamp format and value, key ids).
  • Per-attempt tools: 'Copy cURL for this attempt' rebuilds the historical request from stored keys; 'Verify signature' recomputes the HMAC and reports active/grace match.
  • Timeline filters: search across status, HTTP detail, URL, idempotency key and scheme fields; group by algorithm, timestamp format, encoding, active key id or grace key id.

Signature test console

Paste an event payload and the signature header your endpoint received, choose the scheme configured for that endpoint, and recompute the HMAC here. PlaceRail signs with a shared secret, so verification uses the endpoint's signing secret — there is no public key. Everything runs in this browser tab: the secret is never sent, stored or logged.

Architecture and data-flow diagrams

Four interactive maps of the rail. Hover, tab to, or click any step to read what it does; each diagram is followed by the same content as text so it stays searchable and printable.

Route map

LegendEntry / triggerStandard stepException / riskPrimary pathConditional / exception+Click to expand
after signingreveal logexports

Hover, tab to, or click any step to expand it and trace where it comes from and what follows. The legend above explains the node tones and line styles.

Three access tiers: public marketing and verification pages, tokenised candidate pages that need no account, and the authenticated desk behind the app shell.
  • / landingPublic marketing entry point with links to documentation and sign-in.
  • /docsThis reference, including the signature console and the PDF export.
  • /verifyPublic verification of an exported CSV hash chain and a sealed PDF digest.
  • /authEmail and Google sign-in; issues the session used by every desk route.
  • /sign/:tokenGuided five-step candidate RTR signing flow; no account required.
  • /portal/:tokenCandidate portal: representation status, reveal log and revocation.
  • Authenticated shellSession guard plus navigation for every desk route.
  • Candidates, RTRsOwner-scoped candidate records and representation grants.
  • Listings, job orders, networkDouble-blind supply and demand feeds with 0–100 match scoring.
  • Deals, deal roomsMasked chat, split negotiation, dual signature, reveal, escrow, payouts.
  • Compliance, arbitration, billingIntegrity monitoring, exports, arbitration cases, invoices and payee onboarding.

Event log and integrity flow

LegendEntry / triggerStandard stepException / riskPrimary pathConditional / exception+Click to expand
on mismatch

Hover, tab to, or click any step to expand it and trace where it comes from and what follows. The legend above explains the node tones and line styles.

Every material action is appended to a hash-chained log. The chain is swept on a schedule, sealed into exports, and can be re-verified by anyone holding the files.
  • Material actionRTR signed, agreement executed, reveal, escrow move, dispute or evidence change.
  • Append deal_eventRow written with actor, kind, payload and sequence — inserts only, no updates or deletes.
  • prev_hash → event_hashSHA-256 over the canonical row plus the previous hash, linking every event to its predecessor.
  • Hourly integrity sweepScheduled job re-walks each chain and records a pass or mismatch in integrity_checks.
  • Mismatch alertA broken link notifies the deal parties and surfaces on the compliance dashboard.
  • Signed exportPDF, CSV and ZIP bundle sealed with HMAC-SHA256 and a manifest of digests.
  • Independent verification/verify re-checks chain linkage and the document digest without any account.
  • Compliance webhookBundle delivered to each configured endpoint with a signed, idempotent request.

Escrow lifecycle

LegendEntry / triggerStandard stepException / riskPrimary pathConditional / exception+Click to expand
dispute openedresolvedupheld

Hover, tab to, or click any step to expand it and trace where it comes from and what follows. The legend above explains the node tones and line styles.

Fee splits, guarantee windows and holdbacks are encoded at agreement time; the ledger then advances through fixed states with explicit freeze and reversal branches.
  • Agreement executedSplit %, guarantee days and holdback are locked by dual signature.
  • Funding pendingInvoice issued to the client; escrow waits on the fee landing.
  • Funds heldFee is held against the placement; neither side can pull it unilaterally.
  • Guarantee windowInspection clock runs for the agreed guarantee period before release.
  • ReleasableWindow elapsed with no dispute; split amounts are ready to disburse.
  • Released to both desksExporter and importer paid their split, less any holdback; remittance issued.
  • Frozen by disputeAn open dispute pauses the inspection clock and blocks advancement.
  • Clawback / reversalFall-off inside the guarantee reverses the split per the agreed clawback terms.

Dispute and arbitration flow

LegendEntry / triggerStandard stepException / riskPrimary pathConditional / exception+Click to expand
no agreement

Hover, tab to, or click any step to expand it and trace where it comes from and what follows. The legend above explains the node tones and line styles.

Disputes run on deadlines and per-item evidence visibility. If the parties cannot settle, an arbitrator receives auditable access and issues a locked decision.
  • Dispute openedEither party raises a clawback or performance dispute; escrow freezes immediately.
  • Evidence uploadedEach item carries a visibility setting: private, shared, or released on resolution.
  • Counterparty notifiedIn-app and email notification starts a five-day response deadline with a countdown.
  • Response filedCounter-evidence and a written position land in the same append-only trail.
  • Settled by partiesAgreed outcome unfreezes escrow and writes the settlement to the event log.
  • Routed to arbitratorArbitrator role gets scoped evidence access; every view is recorded.
  • Decision lockedThe ruling is immutable once issued and drives release, holdback or reversal.
  • Sealed dispute exportSigned PDF, CSV and manifest of the whole trail for counsel or a regulator.

Security model

  • Row Level Security on every table, with explicit grants; policies scope reads and writes to deal parties, record owners, org managers or assigned arbitrators.
  • Roles live in a dedicated user_roles table (admin, arbitrator, recruiter) and are checked through the security-definer has_role() function — never stored on profiles, never trusted from the client.
  • PII minimisation: counterparty identity is exposed through masked_profile() (initials, tier, niche tags) until execution; candidate PII is owner-scoped; only the last four TIN digits are stored.
  • Append-only enforcement at the database level via triggers on deal_events, integrity_checks, arbitration_decisions and arbitration_evidence_access.
  • Security-definer helpers (arbitrates_deal, is_case_arbitrator, is_org_member, is_org_manager, detect_noncircumvention, desk_analytics, recruiter_score) re-check auth.uid() internally rather than trusting their arguments.
  • Private storage buckets for dispute evidence and audit exports; access is granted through short-lived signed URLs.
  • Server-only secrets (signing keys, service role) are read inside server-function handlers and never reach the browser bundle.

Data model

DomainTables
Identity & firmsprofiles, user_roles, organizations, organization_members, payee_profiles, subscriptions, invoices
Supply & demandcandidates, rtrs, candidate_portal_access, listings, job_orders, saved_searches
Transactiondeals, split_offers, split_agreements, placements, escrow_transactions
Exceptionsdisputes, dispute_evidence, noncircumvention_flags, arbitration_decisions, arbitration_evidence_access
Evidence & deliverydeal_events, integrity_checks, audit_exports, compliance_endpoints, webhook_signing_secrets, webhook_delivery_attempts
Commsnotifications

Key database functions

FunctionPurpose
has_role(user, role)Role check used by every role-gated policy.
masked_profile(user)Initials, tier and niche tags for pre-reveal display.
verify_deal_event_chain(deal)Recompute one deal's hash chain.
sweep_event_chains()Platform-wide chain sweep for scheduled integrity checks.
rtr_conflict_count(candidate)Competing active representation grants.
detect_noncircumvention(deal)Same candidate at same client outside the recorded split, inside the restricted window.
recruiter_stats / recruiter_score(user)Reputation inputs and the 0–100 banded score.
desk_analytics(user)Pipeline, earned fees, platform fees, outstanding balance, active supply.

Technical architecture

  • Frontend: React 19 + TypeScript on TanStack Start v1 (file-based routing, SSR), Vite 7 build, Tailwind CSS v4 with semantic design tokens, shadcn-style UI primitives.
  • Data layer: TanStack Query for caching and invalidation; route loaders prefetch, components read via suspense queries.
  • Backend: managed Postgres with RLS, storage and auth. App-internal logic runs as typed server functions (createServerFn) with an auth middleware that supplies a request-scoped, user-RLS database client.
  • Public HTTP surfaces (cron, webhook receivers) live as server routes under /api/public/* and authenticate their callers inside the handler.
  • Scheduled work (hourly integrity sweeps, webhook retry worker) runs on database-side cron hitting authenticated endpoints.
  • Client-side document generation for PDFs/CSV/ZIP, with server-side HMAC sealing so documents can be verified independently of the browser that made them.
  • Runtime target is an edge worker: server code sticks to web-standard and Worker-compatible APIs.

Route map

RouteAccessPurpose
/publicLanding
/docspublicThis documentation
/authpublicSign in / sign up
/verifypublicIndependent CSV chain and PDF digest verification
/sign/:tokentokenisedCandidate RTR signing flow
/portal/:tokentokenisedCandidate portal
/dashboardauthenticatedDesk overview and analytics
/candidates · /rtrs · /listings · /job-ordersauthenticatedSupply and representation
/networkauthenticatedBlind feeds, match scoring, saved searches
/deals · /deals/:idauthenticatedDeal rooms and the full transaction stack
/firm · /billing · /payee · /settingsauthenticatedOrg, money and profile
/compliance · /notificationsauthenticatedEvidence, exports, integrity, inbox
/arbitrationarbitratorCase management and locked decisions
/adminadminPlatform administration

Current limitations

  • Escrow, payouts and billing are a demonstration rail — states and documents are real, money movement requires a connected payment provider and licensed escrow agent.
  • Audit emails produce signed download links and a logged send event; true outbound delivery requires a verified sending domain.
  • Invoices are generated client-side per placement rather than persisted as shared records, because counterparty visibility rules differ per party.
  • Candidate identity matching for conflicts and non-circumvention uses normalised email; alias detection is not attempted.
  • No ATS/CRM import connectors yet; supply is entered in-app or via the candidate portal.

Glossary

TermMeaning
ExporterThe recruiter who holds the candidate and the signed RTR.
ImporterThe recruiter who holds the client mandate.
RTRRight to Represent — scoped, signed, time-bound candidate consent.
RevealThe simultaneous unmasking of both parties, triggered by execution of the split agreement.
HoldbackThe portion of a split retained through the guarantee window against fall-off.
ClawbackRecovery of paid fees when a placement falls off inside the guarantee.
Non-circumventionThe restricted window in which a revealed candidate/client pair may not be transacted outside the recorded split.
Hash chainThe linked digest sequence that makes the event log tamper-evident.
Grace periodThe window after a webhook secret rotation during which previous-key signatures are still sent.