🏆
✕
{{ toast.title }}
{{ toast.message }}
Register of Charters
Your Collection Abstract
● {{ currentUser.username }}
Sets
{{ stats.sets }}
Cards Tracked
{{ stats.cards.toLocaleString() }}
Collection Value
${{ Math.round(portfolioValue.collection_value).toLocaleString() }}
—
sets + personal collection
Surplus Value
${{ Math.round(portfolioValue.surplus_value).toLocaleString() }}
—
available to sell
Live Listings
{{ stats.listings }}
Value Change
—
coming soon
Collection
Listings
Value
Unique
Cards Owned
Total Surplus
Cards
Welcome to your Register
Your cartulary is empty — let's fill it. Three steps and you'll have a live eBay listing from your collection.
1
Create a Set
Name your set — 2025 Topps Chrome, 2024 Bowman Draft, whatever you're building.
2
Import Your Cards
Upload a CSV with card numbers and quantities. Download the template from inside your set to get started.
3
Set Keep Quantities
Tell Cartulary how many of each card you want to keep. Everything above that becomes your surplus — ready to list or trade.
Already have a set going? Go to Register →
{{ s.name }}
{{ s.year }} · {{ s.sport }}
{{ (s.owned_count||0).toLocaleString() }}
{{ (s.surplus_qty||0).toLocaleString() }}
{{ s.listed_count||0 }}
${{ (s.collection_value||0).toLocaleString('en-US', {maximumFractionDigits:0}) }}
+${{ (s.surplus_value||0).toLocaleString('en-US', {maximumFractionDigits:0}) }} sellable
${{ (s.completion_cost||0).toLocaleString('en-US', {maximumFractionDigits:0}) }} to finish
—
›
{{ bulkRunText }}
{{ bulkRunFailedNote }}
{{ pillar === 'market' ? 'Market' : 'Register' }}
{{ pillar === 'market' ? 'Your eBay singles inventory' : 'What you own — sets & personal collection' }}
Singles (eBay Individual Listings)
{{ filteredSinglesSets.length }}{{ filteredSinglesSets.length !== singlesSets.length ? ' / ' + singlesSets.length : '' }}
{{ mergeSelected.length }} set{{ mergeSelected.length > 1 ? 's' : '' }} selected
{{ opt.label }}
Sets
{{ variationSets.length }}
{{ s.name }}
Collection Status
{{ (s.owned_count||0).toLocaleString() }}
Owned
{{ (s.surplus_qty||0).toLocaleString() }}
Surplus
{{ s.listed_count||0 }}
Listings
${{ ((s.collection_value||0)+(s.surplus_value||0)).toLocaleString('en-US',{maximumFractionDigits:0}) }}
Value
›
{{ singlesBulkListErrors.length }} failed — {{ singlesBulkListErrors[0].error }}
Delete {{ singlesDeleteSelected.length }} card{{ singlesDeleteSelected.length===1?'':'s' }}?
±
{{ singlesMarketThreshold }}%
{{ sortedSinglesCards.length.toLocaleString() }} cards
{{ bulkUpdateSelected.length.toLocaleString() }} card{{ bulkUpdateSelected.length === 1 ? '' : 's' }} selected
This will consume {{ bulkShare }} eBay's daily limit. eBay allows 5,000
listing updates a day and this press uses {{ bulkSendCount.toLocaleString() }}.
It resets at 2:00am. Nothing is blocked — this is just so the number isn't a surprise.
{{ bulkSkippedNote }}
Tick the cards you want updated, or use one of the choices above.
{{ bulkStartError }}
%
{{ discountSample }}
{{ discountSkippedNote }}
{{ discountMovedNote }}
{{ discountFloorNote }}
This will consume {{ discountShare }} eBay's daily limit. eBay allows 5,000
listing updates a day and this press uses {{ discountCount.toLocaleString() }}.
It resets at 2:00am.
A discount is reversible: Cartulary remembers what each card was really worth and
End & restore puts every one of them back on eBay. Running the same
discount twice is not twice the discount.
Tick the cards you want on sale, then name the discount and pick a percentage.
Loading discounts…
{{ c.name }}
{{ c.pct }}% off
{{ discountStateLabel(c) }}
{{ discountMeta(c) }}
{{ discountConfirmText }}
No discounts yet.
{{ discountError }}
{{ priceMode === 'pct' ? '%' : '$' }}
Or enter a value in the selected card's price field
{{ bulkEditSample }}
{{ bulkEditCampaignNote }}
{{ bulkEditClampNote }}
{{ bulkEditSkipNote }}
{{ bulkEditNotListed.toLocaleString() }} of these cards {{ bulkEditNotListed === 1 ? 'is' : 'are' }} not on eBay yet.
Their price changes here — list them from the Market page when you are ready, or do it now.
This will consume {{ bulkEditShare }} eBay's daily limit. eBay allows 5,000
listing updates a day and this press uses {{ bulkEditListings.toLocaleString() }}. It resets at 2:00am.
Tick the cards you want repriced, then pick how.
{{ bulkEditError }}
Or enter a value in the selected card's qty field
0 ends the listing on eBay. {{ bulkEditEndingCards.length.toLocaleString() }}
listing{{ bulkEditEndingCards.length === 1 ? '' : 's' }} come{{ bulkEditEndingCards.length === 1 ? 's' : '' }} down.
The cards stay in Cartulary with everything on them, and listing them again is the ordinary List button.
{{ c.player }}#{{ c.card_num }}
{{ bulkEditSkipNote }}
{{ bulkEditNotListed.toLocaleString() }} of these cards {{ bulkEditNotListed === 1 ? 'is' : 'are' }} not on eBay yet.
Their quantity changes here — list them from the Market page when you are ready, or do it now.
This will consume {{ bulkEditShare }} eBay's daily limit. eBay allows 5,000
listing updates a day and this press uses {{ bulkEditListings.toLocaleString() }}. It resets at 2:00am.
Tick the cards whose quantity you want to change.
{{ bulkEditError }}
Cards without a value have not been graded by you — the grade was assigned
automatically at upload. Verify and update.
Set all to a grade above, or choose one in the selected card's condition field.
{{ n }}
{{ bulkEditSkipNote }}
This will consume {{ bulkEditShare }} eBay's daily limit. eBay allows 5,000
listing updates a day and this press uses {{ bulkEditListings.toLocaleString() }}. It resets at 2:00am.
Tick the cards you want to grade.
{{ bulkEditError }}
All {{ bulkEditPreview ? (bulkEditPreview.updated || 0).toLocaleString() : bulkUpdateSelected.length.toLocaleString() }}
cards {{ boMode === 'policy' ? 'go back to following your Best Offer settings' : 'are set to never take offers' }}.
{{ bulkEditBoNote }}
This will consume {{ bulkEditShare }} eBay's daily limit. eBay allows 5,000
listing updates a day and this press uses {{ bulkEditListings.toLocaleString() }}. It resets at 2:00am.
Tick the cards whose Best Offer setting you want to change.
{{ bulkEditError }}
Put {{ discountCount.toLocaleString() }} listing{{ discountCount === 1 ? '' : 's' }} on sale at {{ discountPct }}% off and update them on eBay now?{{ discountShare ? ' This will consume ' + discountShare + " eBay's daily limit." : '' }}
{{ bulkEditConfirmText }}
Update {{ bulkConfirmCount.toLocaleString() }} listing{{ bulkConfirmCount === 1 ? '' : 's' }} on eBay now?{{ bulkShare ? ' This will consume ' + bulkShare + " eBay's daily limit." : '' }}
{{ (singlesDisplayOffset + 1).toLocaleString() }}–{{ Math.min(singlesDisplayOffset + singlesDisplayLimit, singlesNavList.length).toLocaleString() }} of {{ singlesNavList.length.toLocaleString() }}
Loading cards…
No cards match the current filters.
| c.id) : []" style="accent-color:#ef4444; cursor:pointer;" /> c.id) : []" style="accent-color:#4ade80; cursor:pointer;" /> | {{ col.label }} {{ allSinglesSort.dir===1 ? '▲' : '▼' }} ⇅ | Market {{ allSinglesSort.dir===1 ? '▲' : '▼' }} ⇅ | vs. Market | {{ col.label }} {{ allSinglesSort.dir===1 ? '▲' : '▼' }} ⇅ | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
{{ c.set_name }} | {{ c.card_num }} | {{ c.player }} | {{ c.card_section }} / {{ c.parallel }} — | {{ c.print_run ? '/'+c.print_run : '—' }} | ${{ (c.price||0).toFixed(2) }} | not checked {{ condShort(c.card_condition) }} | ${{ c.market_price.toFixed(2) }} — | {{ mktBadgeText(c.price, c.market_price) }} — | {{ c.qty ?? 1 }} | {{ new Date(c.single_listed_at).toLocaleDateString('en-US', {month:'short', day:'numeric', year:'numeric'}) }} — | Ended Live ↗ — | {{ c.sku }} — | {{ c.sku_storage_loc }} — |
{{ (singlesDisplayOffset + 1).toLocaleString() }}–{{ Math.min(singlesDisplayOffset + singlesDisplayLimit, singlesNavList.length).toLocaleString() }} of {{ singlesNavList.length.toLocaleString() }}
No sets match the current filters.
{{ s.name }}
{{ s.year || '' }} · {{ s.card_count || 0 }} singles
✓ Checklist
{{ s.checklist_pct || 0 }}%
Complete
{{ s.card_count || 0 }}
Listed
📦 Inventory
{{ inventoryCards.length }} cards · sort: location order
Error: {{ correctLocsError }}
🔒
{{ lockLead }}
{{ lockDetail }}
Locked cards stay listed on eBay, hidden from buyers, and come back when you unlock.
| Location | Listings | State | ||
|---|---|---|---|---|
| {{ r.label }} | {{ r.listings.toLocaleString() }} | {{ r.stateText }} {{ r.deadlineText }} |
Tick the drawers and rows you want closed while you count them.
{{ lockPickedRows.length }} of {{ lockRows.length }} locations selected
{{ lockRunText }}
{{ lockRunFailedNote }}
{{ countSummaryTitle }}
{{ countSummary.where }}{{ f.n.toLocaleString() }}
{{ f.l }}
#{{ x.card_id }} {{ x.reason }} — nothing was created for it.
Found cards that were not on the sheet? Add them with
Bacche, the same way you add any new card.
{{ zeroHeading }}
They are listed in the app but were not in the drawer.| SKU | Location | Player | Set | Card # | Price | |
|---|---|---|---|---|---|---|
| {{ z.sku }} | {{ z.storage_loc }} | {{ z.player }} | {{ z.set_name }} | {{ z.card_num }} | {{ z.price != null ? '$' + Number(z.price).toFixed(2) : '—' }} |
Ends the eBay listing, then deletes the card. A database backup is taken first.
Nothing has been removed yet.
Saving records all {{ inventoryCards.length }} rows shown as counted.
{{ inventoryCountDiffs }} differ from the app.
{{ inventoryCountZeros }} at zero will be nominated for removal.
Pick a drawer-row before saving.
Saving with no filter would record every card in the inventory as counted.
Loading inventory…
| SKU | Location | Player | Card # | Parallel | Qty | Counted | 🏷 |
|---|---|---|---|---|---|---|---|
| {{ c.sku }} — | {{ c.sku_storage_loc }} — | {{ c.player }} | {{ c.card_num || '—' }} | {{ c.card_section && c.card_section.toLowerCase() !== 'base' ? c.card_section : '' }} | {{ c.qty ?? 1 }} |
app says {{ c.qty ?? 1 }}
|
|
| No cards found for this location | |||||||
Personal Collections
{{ pcFolders.length }}
No personal collections yet
Track cards by player, team, year, or any group you choose
{{ f.folder_type === 'player' ? '⭐' : f.folder_type === 'team' ? '🏟' : f.folder_type === 'year' ? '📅' : '📁' }}
{{ f.name }}
{{ f.folder_type }} collection
{{ f.card_count||0 }}
Cards
{{ f.available_count||0 }}
Available
${{ (f.collection_value||0).toLocaleString('en-US',{maximumFractionDigits:0}) }}
Value
›
Drop card images here
Drop as many as you like — AI scans each one automatically. Or click to browse.
{{ bacche_dragover ? 'Drop to add more cards' : 'Drop more images or click to browse' }}
Scanning {{ bacche_processingCount }} of {{ bacche_queue.length }}…
| Player | Set | # | Parallel | Price | Status | ||
|---|---|---|---|---|---|---|---|
|
|
Scanning… {{ item.player || '—' }} RC AUTO | {{ item.set_name || '' }} | {{ item.card_num || '' }} | {{ item.parallel }} /{{ item.print_run }} | ${{ parseFloat(item.price).toFixed(2) }} — | Scanning… Adding… ✓ In Market Error |
{{ bacche_readyCount }} ready to list
· {{ bacche_processingCount }} scanning
· {{ bacche_needsReviewCount }} need review
Review Card
Confirm AI-identified details and set a price
Player *
e.target.style.borderColor='rgba(198,154,68,0.5)'" @blur="e=>e.target.style.borderColor='rgba(255,255,255,0.12)'"
@input="fetchBaccheMarketPrice()">
Set Name *
e.target.style.borderColor='rgba(198,154,68,0.5)'" @blur="e=>e.target.style.borderColor='rgba(255,255,255,0.12)'"
@input="fetchBaccheMarketPrice()">
↑ Matches existing set — select it to avoid creating a duplicate
Card #
e.target.style.borderColor='rgba(198,154,68,0.5)'" @blur="e=>e.target.style.borderColor='rgba(255,255,255,0.12)'"
@input="fetchBaccheMarketPrice()">
Year
e.target.style.borderColor='rgba(198,154,68,0.5)'" @blur="e=>e.target.style.borderColor='rgba(255,255,255,0.12)'">
Parallel / Variation
e.target.style.borderColor='rgba(198,154,68,0.5)'" @blur="e=>e.target.style.borderColor='rgba(255,255,255,0.12)'"
@input="fetchBaccheMarketPrice()">
Print Run
e.target.style.borderColor='rgba(198,154,68,0.5)'" @blur="e=>e.target.style.borderColor='rgba(255,255,255,0.12)'">
Price * (required to mark ready)
$
e.target.style.borderColor='rgba(74,222,128,0.6)'" @blur="e=>e.target.style.borderColor='rgba(74,222,128,0.3)'"
ref="bacche_priceInput">
fetching comps…
({{ bacche_marketSource === 'sold' ? (bacche_marketNote || 'sold comps') : 'market' }}: ${{ bacche_marketPrice.toFixed(2) }})
({{ bacche_marketError }})
{{ bacche_marketSource === 'sold' ? (bacche_marketNote || 'Sold Comps') : 'Active Listings' }}
{{ c.title }}
${{ c.price.toFixed(2) }}
e.target.style.borderColor='rgba(198,154,68,0.4)'" @blur="e=>e.target.style.borderColor='rgba(255,255,255,0.08)'">