Skip to content

Design system

The parts

21 sections, 21 primitives and 64 tokens, each rendered here from the file the theme ships.

Sections
21
Primitives
21
Tokens
64
Type steps
8 at r 1.200

Tokens

Every value, one file

Swatches read from src/theme.css, so this page recolours with the theme.

  • --background
  • --foreground
  • --card
  • --primary
  • --primary-foreground
  • --secondary
  • --secondary-foreground
  • --muted
  • --muted-foreground
  • --accent
  • --accent-foreground
  • --border
  • --ring
  • --primary-hover
  • --primary-active
  • --surface-tint
  • --card-foreground
  • --field
  • --field-border
  • --control-border
  • --control-hover
  • --control-active
  • --selection
  • --selection-foreground
  • --selection-border
  • --info
  • --info-soft
  • --info-border
  • --positive
  • --positive-soft
  • --positive-border
  • --warning
  • --warning-soft
  • --warning-border
  • --critical
  • --critical-soft
  • --critical-border

Display ladder · r 1.200

--text-d4 · 34.6→41.5px fluid · one per page
65%
--text-d3 · 28.8→34.6px fluid · page titles
Relay closes routine tickets
--text-d2 · 24→28.8px fluid · section headings
Read, draft, hand off
--text-d1 · 24px fixed · prices, closing headings
Read, draft, hand off

UI ladder · fixed

--text-lead · 18px/1.6 · ledes
Answered from your data
--text-body · 16px/1.55 · body
Answered from your data
--text-small · 14px/1.45 · UI default
Handed to Dana Okonjo
--text-caption · 12px/1.4 · mono metadata
stripe.invoices.retrieve

Typefaces

--font-text · Public Sans · self-hosted, OFL 1.1

Relay closes routine billing tickets

--font-mono · JetBrains Mono · self-hosted, OFL 1.1

stripe.subscriptions.retrieve · sub_1P7dK2 · 212 ms · +17m04s · $70.97

Radius and hairline

rounded-themed · --radius 0.625rem

rounded-md · the nested step down, 6px

Hairlines never carry structure alone. Every bordered surface also changes background by at least 1.14:1, which is why the border token is tuned for calm rather than contrast.

The thirty-eighth colour is --critical-border. Relay is flat material and ships no shadows; --shadow-color stays declared and unspent.

Primitives

Twenty-one shared parts

Sections never import each other, so anything shared lives in components/ui.

ui

src/components/ui/*.tsx

ui/button

Disabled dims the variant and takes the pointer away; pending is a different thing — the control keeps its label, moves to the info surface, sets aria-busy and refuses a second press.

ui/unavailable-action

Approve and sendEdit draft

Sample console. Approvals run in your helpdesk.

Not a disabled button. A disabled control says something you do could turn it on; these are a picture of the product, so they are a role="button" with aria-disabled, no tab stop, and a dashed edge that says so without an attribute inspector.

ui/badge

read onlyEscalatedAssigned to RelaySampleSuccessApproval timeoutTool error

ui/section-heading

The boundary

What it closes, what it passes

Written down before you switch it on, and enforced in code.

ui/tool-call

docs.search96 ms
query
mid-cycle plan change

Billing policy §3 · match 0.91

ui/chat-turn · three roles, one streaming

Priya Raghunathan

Why was I charged $70.97 on 12 March?

Relay

That charge is the mid-cycle switch to Studio, and

Drafting a reply

Dana Okonjo

Sent by a person

Refund approved and the plan moves back on 1 April.

ui/mode-toggle · one of the theme’s three client islands

Writes the mode class onto the nearest .tt-relay wrapper, or onto the document when the theme runs standalone.

ui/wire-figure renders the two .wire.json graphs in the agent-flow and scope-ledger frames below; ui/logo, ui/container and ui/page-hero render there too

ui/template-summary · automated, approval and handoff

Selected workflow

Duplicate charge

Confirm the duplicate, apply a permitted account credit and send its receipt.

Automated
Sample ticket
ZD-5198
Risk
Routine
Amount
$24.00
Approver
Not required

Close condition

Close after the $24 credit posts and its receipt sends.

Selected workflow

Refund request

Explain the charge, stop at the refund ceiling and hand over the researched case.

Handoff only
Sample ticket
ZD-4821
Risk
Human only
Amount
$70.97
Approver
Dana Okonjo · billing on-call

Close condition

Close only after Dana approves the $70.97 refund and replies.

Selected workflow

Failed renewal

Observe one buyer-owned retry, then send its receipt or preserve a failure handoff.

Automated
Sample ticket
ZD-5274
Risk
Routine
Amount
$149.00
Approver
Not required after the buyer retry succeeds

Close condition

Close after the buyer retry succeeds and its paid receipt reply sends.

Selected workflow

Tax exemption

Gather the certificate, verify required fields and wait for a tax specialist.

Approval required
Sample ticket
ZD-5302
Risk
Needs review
Amount
Not applicable
Approver
Tax specialist

Close condition

Close after a specialist approval note appears and the confirmation reply sends.

ui/boundary-matrix · allowed, conditional and denied

Boundary matrix

Tools and rules

Sample frontend state. Connect these names to your own policy and tool layer.

PermissionToolRule
Allowedstripe.charges.listRead exact amount, invoice and capture time
Allowedpostgres.accounts.readRead account status and current credit balance
Conditionalstripe.credits.writeExact duplicate proven and credit at or below $50
Deniedstripe.refunds.createCash refunds require a person

ui/example-run · success, policy denial, tool error, approval timeout and escalation

Example run

Sample frontend state

Ordered fixtures show why this path closes or stops. No tool executes here.

  1. Sample ticket received

    ZD-5198 enters the billing queue

    Success
  2. Exact duplicate confirmed

    Two $24 captures share one invoice and capture window

    Success
  3. Credit posted

    $24 account credit and receipt recorded

    Success

Example run

Sample frontend state

Ordered fixtures show why this path closes or stops. No tool executes here.

  1. Sample ticket received

    Priya asks about the $70.97 proration charge

    Success
  2. Policy denied the refund

    Billing policy §3 stops a refund above $50

    Policy denied
  3. Research handed over

    Dana receives the invoice, arithmetic, policy and draft

    Escalation

Example run

Sample frontend state

Ordered fixtures show why this path closes or stops. No tool executes here.

  1. Sample renewal checked

    $149 invoice remains open after a card decline

    Success
  2. Buyer retry succeeded

    The payment recovery service reports the invoice paid

    Success
  3. Reply tool failed

    helpdesk.replies.write returned a temporary tool error

    Tool error
  4. Failure handed over

    Billing receives the invoice, decline and failed call ID

    Escalation

Example run

Sample frontend state

Ordered fixtures show why this path closes or stops. No tool executes here.

  1. Sample evidence complete

    Certificate issuer, jurisdiction and expiry are present

    Approval
  2. Approval timed out

    No specialist decision arrived; complete evidence stays in the tax queue

    Approval timeout

Example run

Sample frontend state

Ordered fixtures show why this path closes or stops. No tool executes here.

  1. Sample evidence reviewed

    Issuer and expiry are present, but the jurisdiction is ambiguous

    Success
  2. Relay chose a person

    Relay stops before approval because the jurisdiction needs interpretation

    Voluntary escalation

ui/handoff-contract · ready, complete, missing context and retry

Handoff contract

Evidence for a person

Ready if needed

Evidence attached

  • Both charge IDs
  • Invoice ID
  • Capture times
  • Draft reply

Owner

Billing on-call

Only used when the duplicate match is uncertain

Recovery

A person confirms the match before money moves.

Handoff contract

Evidence for a person

Complete

Evidence attached

  • in_9QtL4M · $70.97 · 12 Mar
  • +$96.13 minus $25.16 over 20 of 31 days
  • Billing policy §3 · $50 ceiling
  • Reply drafted for Priya Raghunathan

Owner

Dana Okonjo · billing on-call

Billing review queue

Recovery

Dana approves, edits or declines the refund from the researched brief.

Handoff contract

Evidence for a person

Retry required

Evidence attached

  • Invoice ID
  • Helpdesk thread
  • Buyer retry receipt
  • Failed call ID

Owner

Billing on-call

Payment recovery queue

Recovery

A person sends the paid receipt after the helpdesk tool recovers.

Handoff contract

Evidence for a person

Complete

Evidence attached

  • Certificate issuer
  • Jurisdiction
  • Expiry date
  • Account country

Owner

Tax specialist

Tax evidence queue

Recovery

The specialist records a decision after the sample approval window.

Handoff contract

Evidence for a person

Missing context

Evidence attached

  • Certificate issuer
  • Expiry date
  • Account country
  • Certificate filename

Owner

Tax specialist

Tax evidence queue

Recovery

The specialist supplies the jurisdiction before requesting approval.

ui/template-checklist · sample, configured and frontend only

Buyer checklist

What you must wire

  • Sample

    Charge reads

    Replace the two sample charge records

  • Configured

    Credit ceiling

    $50 matches the shipped policy sample

  • Frontend only

    Execution

    Connect your Stripe write and receipt job

ui/field

src/components/ui/field.tsx

rest · the hint, and the optional marker in words

Where the answer lands.

Each one publishes its own owner and reply window.

What Relay did or did not do, and on which account.

invalid · the error replaces the hint on the same id

That address has no domain. Add one and try again.

Choose the desk this should reach.

Say a little more. The desk answers faster with the account name in it.

valid · a checked value, and a durable receipt under it

The domain answers.

Security answers against the scope ledger, in two working days.

Enough for the desk to open on.

read-only · the value still matters, so it stays legible and selectable

Taken from the workspace. Change it in settings.

Routed by the workspace's billing owner.

Copied from ticket ZD-4471 when it escalated.

disabled · out of play on a surface of its own, never the resting one at half opacity

Nothing to reply to until a workspace is connected.

The desks arrive with the workspace.

Connect Stripe and a helpdesk first.

submitting · ui/form, the whole fieldset inert

Nothing here takes a keystroke until the request settles.

success · ui/form, the receipt focus lands on

Recorded for Billing and accounts.

Desk
billing@relay.systems
Window
Median 31 min

Held in this page. Nothing reached billing@relay.systems.

Keyboard: the label points at the control, and the one message line under it is named by aria-describedby whichever of the three sentences it is carrying — so a reader who tabs in hears the error, or the receipt, or the hint, and never two of them. Read-only keeps its tab stop and stays selectable; disabled does not, and says so as a surface rather than as half an opacity.

ui/form-error-summary

src/components/ui/form-error-summary.tsx

error-summary · two refused fields, and ui/form's invalid state

invalid · the same submit, with one long message wrapping

Keyboard: the panel is inserted on a refused submit rather than revealed — an always-mounted empty role="alert" announces on every keystroke and says nothing on the submit that matters. It takes focus at tabindex="-1" one render after the refusal, when it exists, and each row is a real link to the field it names.

ui/accordion-disclosure

src/components/ui/accordion-disclosure.tsx

closed

Where does the refund ceiling live?

In config, as a number per rule — not in a prompt. Set it to zero and every refund goes to a person with the draft already written.

Who sees the audit record?

Anyone with the admin scope, and the record names every field the agent read. It is the same log the weekly report is built from.

open

Where does the refund ceiling live?

policy

In config, as a number per rule — not in a prompt. Set it to zero and every refund goes to a person with the draft already written.

Who sees the audit record?

Anyone with the admin scope, and the record names every field the agent read. It is the same log the weekly report is built from.

Keyboard: Enter or Space opens the row, and Escape from inside the answer closes it and puts focus back on the question — the one thing a bare <details> cannot do, and the reason the part is here. Under prefers-reduced-motion the height tween is off and the answer is simply there.

ui/toggle-group

src/components/ui/toggle-group.tsx

default · one option carrying the selection

disabled · an option this account cannot reach

Unavailable is a surface of its own: muted ground, muted ink. It is not the resting option at half opacity.

Keyboard: this set is a radio group. One tab stop, ← and → move between options, and selection follows focus — the model roving plus a single value derives, so what a screen reader announces and what the arrow keys do cannot disagree.

Sections

Twenty-one, in context

Each renders with the content it ships with, and nothing here is a placeholder.

agent-hero

src/components/agent-hero.tsx

Billing queue

Relay closes routine billing tickets and escalates the rest to a person

Proration, invoice copies and card declines, answered from sample Stripe state with the policy section cited.

  • No card to start
  • You approve its first 50 replies
  • Cancel any month

Zendesk ZD-4821

Unrecognised charge on my card

Assigned to Relay

Priya Raghunathan

There is a $70.97 charge on my card from 12 March. I pay $39.00 a month. What is this?

Relay

stripe.subscriptions.retrieve212 ms
customer
cus_QMx7Rb4t
expand
latest_invoice.lines

sub_1P7dK2 · Studio · $149.00/mo

The $70.97 is the mid-cycle switch to Studio on 12 March: $96.13 for the twenty days left, less

Drafting a reply

outcome-band

src/components/outcome-band.tsx

65%

Of billing tickets closed without a human

Our billing queue went from 340 tickets a week to 118 reaching a person.
Marta Oyelaran, support lead at Coilbook

The run on this page

Ticket
ZD-4821
First reply
+1.61s
Calls
6 tools · 1 handoff
Escalated
+17m04s
Closed
24m

The same ticket runs through the transcript, the log and the flow diagram on the product page.

how-it-works

src/components/how-it-works.tsx

How it runs

Read, draft, hand off

Three steps, and the third is the one your team cares about.

  1. 01

    It reads the account

    Relay opens the Stripe subscription, the invoice lines and your accounts table before it writes a word. No answer is composed from the ticket text alone.

  2. 02

    It drafts with a citation

    Every reply names the help-center section it came from. If no section matches above 0.8 confidence, Relay does not send.

  3. 03

    It stops at your line

    Refunds over $50, cancellations and disputes go to a named person with the four facts already gathered and a reply drafted.

boundary-grid

src/components/boundary-grid.tsx

The boundary

What it closes, what it passes

Written down before you switch it on, and enforced in code rather than in a prompt.

Relay closes these

Answered from your data, sent without waiting for anyone.

  • Proration after a mid-cycle plan change
  • Invoice, receipt and VAT copies
  • Card declines and expiring cards
  • Failed payment retries
  • Tax ID and billing address edits
  • Seat counts and what a seat costs
  • Trial end dates and what happens next
  • Account credits up to $50

Relay hands these over

Every time, with the research attached and a reply drafted.

  • Refunds over $50
  • Cancellations and downgrades
  • Chargebacks and disputes
  • Accounts on a signed contract
  • Anything the customer calls a complaint
  • Any policy match below 0.8 confidence

integrations

src/components/integrations.tsx

Sample systems

Six systems, stated access

Read access where it needs it, write access in five places, all listed.

  • Stripe

    read + limited write

    Subscriptions, invoices, charges. Writes credits up to $50 and payment retries.

  • Postgres

    read only

    A read replica of your accounts and entitlements tables. Relay never holds a write credential.

  • Zendesk

    read + write

    Reads the ticket thread, posts the reply or leaves it as a draft for review.

  • Front

    read + write

    Per-inbox. Relay can be switched on for billing and left off for everything else.

  • Intercom

    read + write

    Reads the conversation, replies in-app, and keeps the assignment when it escalates.

  • Slack

    write only

    Posts every handoff into the channel that owns the account, with the facts inline.

conversation-thread

src/components/conversation-thread.tsx

One ticket

A run, end to end

The same ticket the hero opens, played out to the handoff that closes it.

Zendesk ZD-4821 · Coilbook

Unrecognised charge on my card

Escalated

Priya Raghunathan

Email

There is a $70.97 charge on my card from 12 March. I pay $39 a month. What is this?

Relay

stripe.subscriptions.retrieve212 ms
customer
cus_QMx7Rb4t
expand
latest_invoice.lines

sub_1P7dK2 · Studio · $149.00/mo

stripe.invoices.retrieve184 ms
invoice
in_9QtL4M

$96.13 Studio, less $25.16 unused Solo

That charge is the switch to Studio on 12 March. Stripe bills the new plan for the twenty days left in the period and credits the same twenty days you had already paid on Solo, so the invoice is $96.13 minus $25.16.

From 1 April it settles at $149.00 a month on the normal date. Your $39 payments were the old plan and have stopped.

SourceBilling policy §3 · Mid-cycle plan changes

Priya Raghunathan

Email

That makes sense, thank you. Can I have the $70.97 back and go to Solo? We are not using the extra seats.

Relay

Escalated
policy.check14 ms
action
refund
amount
$70.97

blocked · above the $50 ceiling

A refund of this size needs a person. I have passed the thread to Dana Okonjo with the invoice, the plan history and a reply drafted, and told Priya someone will answer today.

Dana Okonjo

Sent by a person

Refund approved and the plan moves back to Solo on 1 April. Priya sees $70.97 returned within five working days.

Closed in 24m6 tool calls1 citation1 handoff

tool-timeline

src/components/tool-timeline.tsx

The run log

Every call, timed

What Relay touched, in what order, and what came back, with nothing hidden behind a spinner.

  1. +0.00sticket.receivedZendesk ZD-4821 · billing intent 0.94
  2. +0.41sstripe.subscriptions.retrieve212 mssub_1P7dK2 · Studio · $149.00/mo
  3. +0.68sstripe.invoices.retrieve184 msin_9QtL4M · $70.97 · 2 lines
  4. +1.09sdocs.search96 msBilling policy §3 · match 0.91
  5. +1.44spolicy.check12 mssend allowed · no money moves
  6. +1.61szendesk.reply.send340 msposted to ZD-4821 · 148 words
  7. +17m02spolicy.check14 msblocked · refund $70.97 over $50
  8. +17m04shandoff.assign88 msescalatedDana Okonjo · billing on-call

agent-flow

src/components/agent-flow.tsx

The decision

Where the run forks

One check decides whether a billing ticket ends with Relay or with a person.

  • trigger

    Ticket arrives

    A billing question lands in the queue with the customer's account id attached.

    • lookup

      Read the account

      Four reads before a word is drafted: Stripe, the accounts replica, the help center, and the ticket's own thread.

      • check

        Does it clear policy?

        Two tests in the tool layer, run before every send: the help center match scores 0.8 or better, and no money moves past $50.

        • clears · 65%

          • step

            Relay answers

            ZD-4821 cleared here at +1.44s. The reply cites the policy section it came from, and a credit up to $50 can go with it.

            • step

              Ticket closes

              The run keeps every call, input and rule that allowed it for 13 months.

              • trigger

                The customer asks again

                ZD-4821 came back at 09:31 wanting the charge refunded, so the same loop ran a second time and met the same check.

                returns to Read the account

        • blocks · 35%

          • handoff

            A person takes it

            The second check stopped ZD-4821: a $70.97 refund against a $50 ceiling.

            • handoff

              Dana gets the brief

              Four facts and a drafted reply: the account, the charge, the payment history, and the rule that stopped it.

One ticket, two checks, and the two endings it chooses between.
Read as text
  1. Ticket arrives

    trigger · starts the run

    A billing question lands in the queue with the customer's account id attached.

  2. Read the account

    lookup · after Ticket arrives · also after The customer asks again

    Four reads before a word is drafted: Stripe, the accounts replica, the help center, and the ticket's own thread.

  3. Does it clear policy?

    check · after Read the account

    Two tests in the tool layer, run before every send: the help center match scores 0.8 or better, and no money moves past $50.

  4. Relay answers

    step · after Does it clear policy? · branch clears (65%)

    ZD-4821 cleared here at +1.44s. The reply cites the policy section it came from, and a credit up to $50 can go with it.

  5. Ticket closes

    step · after Relay answers

    The run keeps every call, input and rule that allowed it for 13 months.

  6. The customer asks again

    trigger · after Ticket closes

    ZD-4821 came back at 09:31 wanting the charge refunded, so the same loop ran a second time and met the same check.

  7. A person takes it

    handoff · after Does it clear policy? · branch blocks (35%)

    The second check stopped ZD-4821: a $70.97 refund against a $50 ceiling.

  8. Dana gets the brief

    handoff · after A person takes it

    Four facts and a drafted reply: the account, the charge, the payment history, and the rule that stopped it.

handoff-panel

src/components/handoff-panel.tsx

The handoff

What the person receives

The account, the charge, the rule that stopped it, and a reply ready to send.

Handed to Dana Okonjo

billing on-call · 09:31

What Relay gathered

Account
Coilbook · Studio · customer since 4 Jan 2024
Charge
in_9QtL4M · $70.97 · 12 Mar
History
$1,085 paid · 0 disputes · 0 late invoices
Rule hit
Refund ceiling $50 · exceeded by $20.97

Drafted reply

Hi Priya, I have approved the $70.97 back to your card and moved you to Solo from 1 April. The refund lands within five working days.

Approve and sendEdit draft

Sample console. Approvals run in your helpdesk.

Stopped by refund.ceiling, not by a hunch.

guardrails

src/components/guardrails.tsx

Guardrails

Four rules, enforced in code

Your security review will ask these four questions, so here are the answers first.

refund.ceiling

It cannot move money over $50

The ceiling is a number in your config, checked in the tool layer before the call is made. A prompt cannot argue with it.

policy.threshold

It cannot send an uncited answer

Below 0.8 match against your help center, Relay drafts and escalates instead of sending. The threshold is yours to move.

db.readonly

It holds no write credential

Account data comes from a read replica. There is no path from Relay to a row in your primary database.

audit.retain

Every action keeps its cause

Each call is logged with the ticket, the inputs and the rule that allowed it, kept 13 months and exportable as CSV.

scope-ledger

src/components/scope-ledger.tsx

Access

Every scope Relay holds

Three of these eight scopes can write, and only one of the three moves money.

  • trigger

    Eight scopes are held

    Six systems, one credential each: a restricted Stripe key, a read-only replica role, an OAuth app per inbox, and one Slack bot token.

    • check

      Can the scope write?

      The credential decides, not the prompt. A read-only role cannot be talked into a write.

      • reads · 5 of 8

        • lookup

          Five only read

          Stripe subscriptions and invoices, the accounts replica, the help center and the ticket thread. Nothing they touch changes.

      • writes · 3 of 8

        • step

          Three can write

          One reply per ticket, one handoff message, and account credits. Every write is scoped to a single object.

          • check

            Does the write move money?

            Two of the three writes only post text. The third is the only path from Relay to your balance.

            • words · 2 of 3

              • step

                Two post text

                helpdesk.replies.write posts one reply on one ticket. slack.handoff.write posts into the one channel that owns the account.

            • money · 1 of 3

              • limit

                One moves money, capped at $50

                stripe.credits.write is checked against the ceiling in the tool layer, before the call is made.

                • handoff

                  The refund goes to a person

                  ZD-4821 asked for $70.97 against the $50 cap, so the scope was never used and Dana Okonjo answered instead.

Eight scopes narrow to one that can move money, and that one stops at a number.
Read the model as text
  1. Eight scopes are held

    trigger · starts the run

    Six systems, one credential each: a restricted Stripe key, a read-only replica role, an OAuth app per inbox, and one Slack bot token.

  2. Can the scope write?

    check · after Eight scopes are held

    The credential decides, not the prompt. A read-only role cannot be talked into a write.

  3. Five only read

    lookup · after Can the scope write? · branch reads (5 of 8)

    Stripe subscriptions and invoices, the accounts replica, the help center and the ticket thread. Nothing they touch changes.

  4. Three can write

    step · after Can the scope write? · branch writes (3 of 8)

    One reply per ticket, one handoff message, and account credits. Every write is scoped to a single object.

  5. Does the write move money?

    check · after Three can write

    Two of the three writes only post text. The third is the only path from Relay to your balance.

  6. Two post text

    step · after Does the write move money? · branch words (2 of 3)

    helpdesk.replies.write posts one reply on one ticket. slack.handoff.write posts into the one channel that owns the account.

  7. One moves money, capped at $50

    limit · after Does the write move money? · branch money (1 of 3)

    stripe.credits.write is checked against the ceiling in the tool layer, before the call is made.

  8. The refund goes to a person

    handoff · after One moves money, capped at $50

    ZD-4821 asked for $70.97 against the $50 cap, so the scope was never used and Dana Okonjo answered instead.

  • stripe.subscriptions.read

    Stripe

    read

    Restricted API key

    Plan, period and the proration lines behind a charge

  • stripe.invoices.read

    Stripe

    read

    Restricted API key

    Invoices, charges and receipts

  • stripe.credits.write

    Stripe

    write

    Restricted API key

    Account credits capped at $50, the only scope that moves money

  • postgres.accounts.read

    Postgres replica

    read

    Read-only replica role

    Entitlements, seat counts and trial end dates

  • docs.search

    Help center

    read

    Public URL, no key

    Published articles, for the citation on every reply

  • helpdesk.threads.read

    Zendesk · Front · Intercom

    read

    OAuth app, per inbox

    The ticket thread and its history

  • helpdesk.replies.write

    Zendesk · Front · Intercom

    write

    OAuth app, per inbox

    One reply per ticket, sent or left as a draft

  • slack.handoff.write

    Slack

    write

    Bot token, one channel

    The handoff message, in the channel that owns the account

Five systems accept a write. The accounts replica is read only, and no scope reaches your primary database.

audit-record

src/components/audit-record.tsx

Audit

The record every call leaves

A blocked call keeps the same fields as a sent one, so nothing is missing.

13 months

Kept on every row

Exported as CSV from the console, or read through the audit API with a scoped key.

Processed in eu-west-1. Three sub-processors: the model provider, the cloud host and the error store.

One row, in full

audit.log · row 7 of 8
ticket
ZD-4821
call
policy.check
inputs
refund · $70.97 · in_9QtL4M
rule
refund.ceiling · $50
outcome
blocked · exceeded by $20.97
at
09:31 · +17m02s
kept until
12 Apr 2027

The seven other rows from this run are on the run log. Read all eight

pricing-table

src/components/pricing-table.tsx

Plans

You pay for closed tickets

A ticket Relay hands to a person still cost you that person, so it is not billed.

Starter

$290per month

500 closed tickets a month

$0.60 per ticket after that

  • One helpdesk and Stripe
  • Reply drafting and sending
  • Handoff to a named person
  • 13-month audit log
Start free for 14 days

Team

Most chosen

$890per month

2,500 closed tickets a month

$0.42 per ticket after that

  • Every integration, including Postgres
  • Approval queues per rule
  • Custom ceilings and thresholds
  • Slack handoff routing
  • Weekly accuracy report
Start free for 14 days

Scale

Customannual

Unmetered closed tickets

Priced against last quarter's volume

  • SSO and SCIM
  • Your cloud or ours
  • Named support engineer
  • 99.9% uptime commitment
Talk to sales

$0

For every ticket Relay hands to a person. Escalations are the ones that still cost you a salary, so they are not on the invoice.

  • No card to start
  • You approve its first 50 replies
  • Cancel any month

price-estimator

src/components/price-estimator.tsx

Your volume

What that would cost

Move the slider to the tickets you close in a month and the plan follows the number.

Coilbook, the account in the run log, closes about 950 a month.

Starter
$560
Team
$890

Cheapest plan

$560a month on Starter

$0.59 per closed ticket

Tickets Relay hands to a person are not counted, so this is the whole invoice.

support-desk

src/components/support-desk.tsx

Where to write

Four desks, named owners

Each one states who reads it and how long you wait, because that is the product's own claim.

  • Billing and accounts

    Median 31 min

    billing@relay.systems

    Invoices, proration and anything Relay escalated to a person on your queue.

    Dana Okonjo, billing on-call

  • Rollout and setup

    Same working day

    support@relay.systems

    Connecting Stripe and a helpdesk, moving a ceiling, tuning the 0.8 threshold.

    The engineer who built your connector

  • Security review

    Two working days

    security@relay.systems

    Scopes, sub-processors and the DPA. Most of it is already written down.

    Answered against the scope ledger

  • Something is wrong

    24 hours a day

    +44 20 7946 0227

    Relay sent something it should not have, or stopped sending at all.

    The on-call engineer, not a queue

31 min

Median reply on billing, last quarter

Measured from the message arriving to a person answering it, not to an autoresponder. The slowest 5% took under four hours.

Who you are contracting with

registered details
Entity
Relay Systems Ltd
Registered
Company 11482996, England and Wales
Office
Ashby House, 4 Hoxton Square, London N1 6NU
Data region
eu-west-1, with three sub-processors
Data controller
privacy@relay.systems

Scopes, retention and the sub-processor list are on the security page.

request-form

src/components/request-form.tsx

Send it on

Ask one of them directly

Pick the desk, say what happened, and the receipt tells you who has it and how long you wait.

This is the frontend. The request is validated and receipted in the page and nothing is transmitted — point the form at your own endpoint and the same four states carry through.

Workspace
Coilbook, eu-west-1
Last run
ZD-4821 · 6 tool calls
Kept
13 months, with the audit log
Request details

Each one publishes its own owner and reply window.

Where the answer lands.

A ticket or invoice id, if there is one.

What Relay did or did not do, and on which account.

template-index

src/components/template-index.tsx

Workflow library

Choose a bounded workflow

Filter four sample paths, then inspect tools, stop rules and handoff evidence.

Matches the workflow name, its summary and its tools.

Risk level

4 workflows shown

Selected workflow

Refund request

Explain the charge, stop at the refund ceiling and hand over the researched case.

Handoff only
Sample ticket
ZD-4821
Risk
Human only
Amount
$70.97
Approver
Dana Okonjo · billing on-call

Close condition

Close only after Dana approves the $70.97 refund and replies.

Boundary matrix

Tools and rules

Sample frontend state. Connect these names to your own policy and tool layer.

PermissionToolRule
Allowedstripe.subscriptions.retrievesub_1P7dK2 · Solo $39 to Studio $149
Allowedstripe.invoices.retrievein_9QtL4M · +$96.13 minus $25.16
Alloweddocs.searchBilling policy §3 · refund ceiling $50
Deniedstripe.refunds.create$70.97 exceeds the $50 ceiling by $20.97

Example run

Sample frontend state

Ordered fixtures show why this path closes or stops. No tool executes here.

  1. Sample ticket received

    Priya asks about the $70.97 proration charge

    Success
  2. Policy denied the refund

    Billing policy §3 stops a refund above $50

    Policy denied
  3. Research handed over

    Dana receives the invoice, arithmetic, policy and draft

    Escalation

Handoff contract

Evidence for a person

Complete

Evidence attached

  • in_9QtL4M · $70.97 · 12 Mar
  • +$96.13 minus $25.16 over 20 of 31 days
  • Billing policy §3 · $50 ceiling
  • Reply drafted for Priya Raghunathan

Owner

Dana Okonjo · billing on-call

Billing review queue

Recovery

Dana approves, edits or declines the refund from the researched brief.

Buyer checklist

What you must wire

  • Sample

    Invoice reads

    The fixture uses in_9QtL4M

  • Configured

    Policy rule

    The $50 ceiling matches Relay's sample

  • Frontend only

    Approval action

    Connect your queue and refund executor

Long label

Cross-border tax exemption with an expired certificate and an unresolved jurisdiction rule

No result

No workflows match these filters.

Clear filters returns focus to search.

faq

src/components/faq.tsx

Questions

Asked before every rollout

The answers a support lead needs before they will let an agent near the queue.

Can Relay issue a refund on its own?

Only account credits up to $50, and only when your config allows it. Anything above the ceiling goes to a person with the draft written. The ceiling can be set to zero on day one.

What happens when it gets something wrong?

Every reply names the policy section it used, so a wrong answer is traceable to a wrong document. The weekly report lists each reply a customer pushed back on, and you can move the confidence threshold up until it stops.

How long does setup take?

About an hour. You connect Stripe read keys and one helpdesk, point Relay at your help center, and set the refund ceiling. You approve its first 50 replies before it sends on its own.

What does it do with our customer data?

It reads the ticket, the Stripe record and a read replica of your accounts table. Nothing is used for training, and the audit log records every field it touched.

Does it work on a helpdesk you do not list?

There is an HTTP integration for anything with a webhook and a reply endpoint. Zendesk, Front and Intercom are the ones we maintain directly.

What if our billing rules are unusual?

Ceilings, thresholds and escalation routes are per-rule config rather than a prompt. Teams with annual contracts usually route those accounts to a person and let Relay take the monthly ones.

cta

src/components/cta.tsx

Put Relay on the billing queue

Connect Stripe and one helpdesk, approve its first 50 replies, then let it send.

  • No card to start
  • You approve its first 50 replies
  • Cancel any month

ui/page-hero

src/components/ui/page-hero.tsx

Inside a run

Every step one ticket took

Ticket ZD-4821 arrived at 09:14 and closed at 09:38.

Tool calls
6
Handoffs
1