> ## Documentation Index
> Fetch the complete documentation index at: https://www.twicecommerce.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# How to build a price table and share it across listings

> Create a rate card, tier it so a week costs less per day than a day does, attach it to many listings, and know what changes when you edit it.

<Card title="Open in TWICE Admin" icon="external-link" href="https://admin.twicecommerce.com/catalog/pricing-tables" horizontal>
  Catalog → Price Tables
</Card>

A price table is a rate card. One object holds the prices for a selling mode, and any number of listings can point at it — so re-pricing a category is one edit rather than forty.

This guide builds a shared table and tiers it by duration. If you only need to price a single listing, [price a listing](/docs/guides/catalog/price-a-listing) does that from the listing's own Pricing tab and is the shorter road.

## Prerequisites

<Warning>
  **Required permission:** `catalog:price_table`. Linked listings are a separate gate — `catalog:price_table_linked_listings` — so a role can be able to edit prices without being able to see which listings they affect.
</Warning>

<Info>
  **A shared table is a shared consequence.** The reason to build one is that editing it re-prices every listing linked to it at once. That is the feature, and it is also the trap: the *Linked listings* tab is the only thing standing between a routine price edit and forty listings changing.

  Check that tab before you edit an existing table, not after.
</Info>

## The Walkthrough

<Steps>
  <Step title="Create the table — it exists immediately">
    Go to **Catalog → Price Tables** and click **Create Table**.

    There is no dialog. TWICE creates the table straight away, names it **Unnamed**, and opens it. The steps below are editing a table that already exists.
  </Step>

  <Step title="Name it, and decide whether it is dated">
    On the **General** tab, **Details** holds two fields.

    **Name** is how you will recognise it in the picker when you attach it to a listing. It is internal — customers never see it — so name it after what it prices ("Standard bike rates"), not after a listing.

    **Validity** is the date window. Leave it empty and the table is always in play. Set it and the table's rows only become candidates inside that window.

    **Leave Validity empty on this table.** *Only price tables without a validity period can be used as a listing's default price table* — a dated table cannot be attached as a listing's default, and it does not override one. Dated tables are a separate job — they layer over a default rather than replacing it, and the troubleshooting below covers what that does and does not let you charge.
  </Step>

  <Step title="Turn on the selling modes you actually use">
    The **Prices** card — *set the prices and purchase types for the table* — holds three independent sections: **Purchase price**, **Booking price** and **Subscription**.

    One table can carry all three. Turn off the ones you do not sell; the rows stay but the editing surface stops offering them.
  </Step>

  <Step title="Choose fixed or rate-based booking prices">
    Booking prices come in two shapes, and the choice decides what the customer does on the storefront.

    * **Fixed price for duration** — *fixed prices for specified periods — e.g. 1 day or 3 hours.* The customer picks one of your rows. Add them with **Add fixed duration price**.
    * **Rate-based** — the customer picks any start and end, and the engine prices the span from your rows. Add them with **Add rate-based price**.

    Most rate cards are rate-based, because that is what makes tiering do any work. A fixed-price table with a day row and a week row offers exactly two options; a rate-based one covers everything in between.
  </Step>

  <Step title="Set the duration tiers">
    This is the actual rate card. Add one row per tier, each with a **Period** (a number and a unit) and a **Base price**:

    | Period | Base price |
    | ------ | ---------- |
    | 1 day  | €40        |
    | 3 days | €100       |
    | 1 week | €180       |

    The tiering is what makes a week cheaper per day than a day is. You do not configure a discount — you price the longer block lower per unit, and the engine does the rest.

    **How the engine chooses.** For each part of the booking it prefers the row with the **longest duration that still fits**, breaks ties on the **lowest price**, and fills any remainder with shorter rows and the **Additional price** rule. So a 9-day rental off the table above resolves as a week plus the rows that best cover the remaining two days — not as nine day-rows.

    Add rows at the durations customers actually book. A gap between 1 day and 1 week means every mid-length rental is priced out of day-rows.
  </Step>

  <Step title="Decide how a partial period is charged">
    Each row carries a pricing model, and it is the setting most worth getting right.

    **Starting at pricing** — *charge for every calendar period the booking touches: a 23:00 pickup and a 01:00 return counts as two days.* With it off, prices are charged by booked duration — *a day is 24 hours from pickup*.

    The unit dropdown names it per row: **Day (Elapsed)** versus **Day (Started)**.

    This is a revenue decision, not a display one — it is the difference between a ski hire and a plant hire. [Price a listing](/docs/guides/catalog/price-a-listing) works through the reasoning; the choice you make there applies here.

    Sub-hour rows are always charged by duration, whatever the table's model.
  </Step>

  <Step title="Attach the table to listings">
    A table with no listings pointing at it prices nothing. Attaching happens from the listing, not from the table: open a listing's **Pricing** tab and pick this table.

    The picker only offers **shared tables with no validity period**, which is the same constraint from step 2 seen from the other end.

    The table's **Linked listings** tab — *listings using this price table* — then lists everything attached, with **Unlink** on each row. That tab is your blast radius.
  </Step>
</Steps>

## How do I know it worked?

The table appears in **Catalog → Price Tables** with its **Name**, its **Validity**, and a **Linked listings** count. That count going up is the confirmation that attaching worked.

The check that proves the *tiering* works is a real quote. Open one of the linked listings on the storefront and price a duration that should land on a longer tier — a 7-day rental on the table above should come out at €180, not 7 × €40. If it comes out as the sum of day-rows, the week row is not being selected, and the troubleshooting below covers why.

## Troubleshooting / Common Pitfalls

<AccordionGroup>
  <Accordion title="Editing the table changed prices on listings I wasn't thinking about">
    **Working as designed, and the reason shared tables exist.** Every linked listing re-prices together.

    **What to do:** open **Linked listings** before editing. If one listing needs to move independently of the others, give it its own table rather than editing the shared one — the shared table is the wrong instrument for a one-listing change.
  </Accordion>

  <Accordion title="A long rental is priced as a stack of day-rows">
    **Cause:** no longer row covers it, or a longer row exists but is more expensive per booking than the composition of shorter ones. The engine takes the cheapest valid coverage, so an over-priced week row simply never gets selected.

    **What to do:** check the week row is enabled, and check its price against 7 × the day row. A week priced at or above seven days is not a tier — it is a row that will never win.
  </Accordion>

  <Accordion title="I set a higher holiday rate and customers still get the normal price">
    **Cause:** a dated table does not override the default — its rows compete in the same pool, and the cheaper row wins.

    **What to do:** a *cheaper* promotional row works with no further effort. A *higher* one does not, and needs the competing default row removed or date-restricted for that window so nothing cheaper covers it. The mechanism is set out in [Price resolution](/docs/concepts/catalog/price-tables#price-resolution).
  </Accordion>

  <Accordion title="I cannot attach my dated table to a listing">
    **Working as designed.** Only tables without a validity period can be a listing's default, and the picker filters to those.

    **What to do:** keep an undated table as the baseline and let dated tables layer over it. A dated table is an overlay, never a substitute for having a default.
  </Accordion>

  <Accordion title="Part of a booking has no price">
    **Cause:** rows carry optional **weekday**, **time of day** and **date** restrictions, and a segment matching none of them falls through.

    **What to do:** give at least one row a fallback price so any uncovered segment has something to resolve against. Where several rows offer one, the cheapest applicable wins.
  </Accordion>

  <Accordion title="The same listing needs different prices per location or per channel">
    **Not available.** A table is scoped by validity period and nothing else. There is no per-location or per-channel price.

    **What to do:** two locations that must charge differently need separate listings with separate tables — which also means separate stock rules and separate publishing. Worth being sure the difference justifies that.
  </Accordion>

  <Accordion title="I want a rate for one customer segment">
    **Not on a price table.** There is no per-customer-tag pricing in the model.

    **What to do:** use a [discount code](/docs/guides/catalog/create-a-discount-code) restricted to the listings or collections in question. A staff-only code covers the contract-rate case.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Price a listing" icon="tag" href="/docs/guides/catalog/price-a-listing">
    The single-listing road, and the Elapsed versus Started reasoning in full.
  </Card>

  <Card title="Price tables" icon="table-cells" href="/docs/concepts/catalog/price-tables">
    The model behind tables, rows, and resolution.
  </Card>

  <Card title="Price Tables view" icon="list" href="/docs/catalog/price-tables">
    The view reference, field by field.
  </Card>

  <Card title="Create a discount code" icon="percent" href="/docs/guides/catalog/create-a-discount-code">
    Taking money off a price rather than changing it.
  </Card>
</CardGroup>
