tailthemesbuy this theme · $39
Skip to content

Design system

The parts

Nineteen sections, ten primitives and eighteen colours, each rendered here from the same file the theme ships.

Sections
19
Primitives
10
Colours
18 × 2 modes
Type steps
8 at r 1.200

Tokens

Every value, one file

Swatches read live 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

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 eighteenth colour is --shadow-color. Relay is flat material and ships no shadows, so the token is declared and never spent.

Primitives

Ten shared parts

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

ui

src/components/ui/*.tsx

ui/button

ui/badge

read onlyEscalatedAssigned to Relay

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 two 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

Sections

Nineteen, 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 live Stripe data 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 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

Connected 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.

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.

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