GoatLabels GoatLabels
Three flows, one clean ledger.

Shipping in your books: postage, income, and corrections


Entries a bookkeeper can copy today.

Shipping shows up in your books three ways: postage you paid, shipping income you charged the buyer, and after-the-fact corrections — refunds on voided labels and carrier adjustments. Clean books track all three per order, so margin reflects what delivery actually cost, not what the label cost at purchase.

All-in prices make clean entries

USPS, UPS, FedEx, and DHL each quoted as one number that includes surcharges, insurance, and signature fees — so one label is one ledger line, not five.

UPSFedExDHLUSPS all four
One line per label Nothing to unbundle.
Corrections visible Own records, own dates.
Margin per order True delivered cost.

The wallet is an asset, labels are the expense

Top-ups by card, Apple Pay, Google Pay, ACH, or crypto are asset transfers — the expense posts per label as the balance draws down.

VisaMastercardAmerican ExpressApple PayGoogle PayBitcoinEthereumTether (USDT)
Top-up ≠ expense Asset in, asset out.
Voids reverse cleanly Credit back to balance.
History via API Pull any period.

COGS or expense: where postage belongs, and why sellers disagree

Sellers argue about this because the word shipping covers three different money flows wearing one name. Postage you pay to send customer orders is a cost of selling. Freight you pay to receive inventory is part of what that inventory cost you. And the shipping line buyers pay at checkout is not a cost at all — it is revenue. Most of the confusion in a small seller's books comes from letting those three share an account, at which point no report can say what delivery actually earns or costs.

The defensible positions are narrower than the arguments suggest. Outbound postage on customer orders is most commonly booked as a selling or operating expense; inbound freight belongs with the inventory it carried. Some sellers fold outbound postage into cost of goods sold so that gross margin reflects delivered cost — also workable, provided it is deliberate. The real rule is the boring one: split the flows, choose a treatment with whoever prepares your taxes, write it down, and never change it silently. A margin figure is only useful if this month was computed the same way as last month.

One account deserves special mention because almost everyone gets it wrong at first: the prepaid wallet. Funding a shipping balance is not an expense — it is cash becoming a different asset, and the expense happens later, label by label, as the balance draws down. Booked this way, your postage expense lands in the period the parcels actually shipped, not the day you happened to top up.

Account Type What posts here
Prepaid shipping wallet Other current asset Wallet top-ups in; label purchases, insurance premiums, and signature fees out; void credits back in; adjustments out.
Postage expense (or COGS — shipping) Expense The all-in cost of each label as it is bought, plus adjustments; reduced by void credits. Pick expense or COGS with your accountant and stay put.
Shipping income Income What buyers paid you for delivery, booked with the sale — never netted against postage.
Inbound freight Inventory / COGS Carriage on inventory you purchased. Kept separate from outbound postage so the two flows never blur.

Shipping income: booking what you charged the buyer

Whatever the buyer paid you for delivery is income, and it deserves its own income account rather than being quietly subtracted from postage expense. Netting the two feels tidy and destroys the one comparison a small seller most needs: shipping income against postage expense, side by side on the profit and loss, telling you whether your checkout shipping prices are funding your actual delivery costs. Sellers who net them discover they have been subsidising delivery only when the year-end totals refuse to add up.

The edge cases are worth naming. Free shipping means zero shipping income and full postage expense — the subsidy is real, so let the books show it rather than bury it. Flat-rate checkout shipping against live-rated postage means the two accounts will never match per order, and that gap is your pricing decision made visible, not an error. And marketplaces that collect shipping from the buyer and pass it through a payout need reading carefully: book what the payout report says you received for shipping, which is not always what the buyer saw at checkout.

The corrections: void credits and adjustments as journal entries

Corrections are where shipping bookkeeping earns its keep, because both kinds arrive after the sale they belong to. A voided label comes back as a wallet credit, spendable immediately — the mechanics and deadlines live on the void a shipping label page. A carrier that reweighs or remeasures a parcel bills the difference after delivery; how each carrier detects, bills, and lets you dispute that is the carrier billing adjustments page's territory. Here is what both look like as entries, using deliberately invented round numbers — copy the shape, not the figures.

Event Debit Credit Note
Fund the wallet with $200 Prepaid shipping wallet $200 Cash $200 No expense yet — money moved between assets.
Buy a label for $9 Postage expense $9 Prepaid shipping wallet $9 The expense happens here, at purchase, per order.
Void that label; credit granted Prepaid shipping wallet $9 Postage expense $9 The mirror of the purchase, dated when the credit posted.
Carrier adjustment of $3 posts Postage expense $3 Prepaid shipping wallet $3 Referenced to the original shipment so its margin updates too.

Three habits keep the corrections honest. Date every entry on the day the money actually moved — the day the credit posted or the adjustment hit — not the day of the original label, so each period carries its own truth. Reference each correction to its original shipment, so the order's margin updates instead of the correction floating loose in a miscellaneous account. And record one nuance exactly as it happens: when an adjustment exceeds the wallet balance, the remainder is charged to the card on file, so that entry credits the card liability, not the wallet, because books should say where money really came from.

Getting shipment history out: exports and the API

A chart of accounts is only as good as the records feeding it, and this is where the platform does the bookkeeper a favour: every event above is its own record. A label purchase, a void credit, and an adjustment each exist as separate entries with their own dates and amounts, visible in the dashboard ledger — never a silently edited balance you have to reverse-engineer at quarter end.

For getting that history into your accounting workflow, the bridge is the REST API: shipments and their adjustments are readable as records for any period, calls are unlimited on every plan, and the current endpoints are documented in the API docs. To be plain about the boundary — there is no ready-made connector for any specific accounting package, and this page will not pretend otherwise. A short script, or the tooling your bookkeeper already runs against APIs, pulls the period's rows; teams that want entries posted the moment a correction lands wire up the signed webhooks instead, and the webhook recipes page walks through that consumer end to end. Either way the goal is the same as this whole page's: a ledger where every parcel's true delivered cost is one lookup away.

From one parcel to three dated records

One label bought. One entry, on the day it happened.

Shipping bookkeeping is only hard when the source records are vaguer than the accounts they feed. This flow produces exactly what a ledger wants and nothing it has to unpick: a top-up that moved cash from one asset into another, a purchase that posted a dated expense at a single all-in amount, and — when a correction lands weeks later — its own entry carrying its own date and a reference back to the shipment it belongs to. Nothing is netted, nothing is a silently edited balance, and no figure has to be reverse-engineered at quarter end.

1
The order, before any account is touched
Nothing has posted yet
order email

one parcel to Austin, TX — invoice attached

Shopify
Synced order — same expense account
TikTok Shop
Synced order — same wallet asset
What the journal entry will need
Date
The day the label was bought, not the top-up
Amount
One all-in price, not four separate fees
Account
Postage expense or COGS — chosen once, kept
Reference
The shipment, so the order's margin updates
Paste the order, or let a connected store sync it

Funding the wallet is not the expense. A top-up debits an asset and credits cash; the expense posts later, label by label, in the period the parcels actually shipped.

2 Billy AI

Drafted once, so the entry matches the parcel.

Billy AI
  • Reads the buyer, the address, and the parcel out of a pasted order or a screenshot
  • Validates the address before anything posts — a re-buy is two entries plus a void to unwind
  • Rate-shops the parcel so the amount you book is the amount you chose, not a default carrier's
  • Included on every plan, so nothing about clean books arrives as a separate software expense
Address validated. One purchase, one line.
3
The purchase posts
Debit postage expense, credit the wallet
Prepaid wallet drawn down
An asset account, never a monthly bill
all-in
USPS
Label bought at the quoted price
One ledger line, nothing to unbundle
all-in

Corrections come later and get their own dated entries — a void credit as the mirror of this purchase, a carrier adjustment as a separate line referenced to the same shipment. The entries are in the table above; what those two events actually are belongs to the void a shipping label and carrier billing adjustments pages.

Every channel, one postage account

Orders from anywhere, one expense account.

Shopify, Etsy, WooCommerce, and TikTok Shop sync into the same To Ship queue, and a pasted DM or a typed address lands in it too. That matters to your books more than it looks: however the order arrived, the label posts the same way — one dated debit to postage expense, one credit to the prepaid wallet — so channel mix never turns into an account-mapping exercise at month end.

Via AItiles: pasted orders and screenshots post exactly like synced ones — same account, same date rule, same reference.

Shopify logo Shopify
Etsy logo Etsy
WooCommerce logo WooCommerce
TikTok Shop logo TikTok Shop
Instagram logo Instagram AI Facebook logo Facebook AI
Amazon logo Amazon
eBay logo eBay
Show 15 more Show less
Squarespace logo Squarespace
Wix logo Wix
Walmart logo Walmart
Shopify Plus logo Shopify Plus Soon
Square logo Square
BigCommerce logo BigCommerce
Magento logo Magento
Zapier logo Zapier Soon
NetSuite logo NetSuite Soon
Ecwid logo Ecwid Soon
Temu logo Temu
Shein logo Shein Soon
ChannelAdvisor logo ChannelAdvisor Soon
SkuVault logo SkuVault Soon
Zoho Inventory logo Zoho Inventory Soon
Five things that decide how clean the entries are.

Built so the ledger stays
one line per parcel.

Nothing below is an accounting feature. They are ordinary shipping mechanics that happen to determine whether a bookkeeper gets one dated record per event or a balance to reverse-engineer.

The wallet is an asset,
the label is the expense

Top-ups by card, Apple Pay, Google Pay, ACH, or crypto move cash into a prepaid balance — an asset-to-asset transfer with no expense in it. The expense posts per label as the balance draws down, which is what puts your postage in the period the parcels shipped rather than the period you happened to top up.

Wallet balance
$1,247.36 USD
AI

Fewer re-buys,
fewer entries to unwind

Billy drafts the label from a pasted order or a screenshot and validates the address before money moves. Every avoided mistake is an entry you never have to write: a bad address means a purchase, a void credit, and a second purchase where one line should have been.

Billy LIVE
Where's the package to Maya?
It's in transit via UPS. Expected Friday, Aug 7.
UPS
1Z8923A6B05G4123456
In transit
Austin, TX → Dallas, TX
Ask Billy anything...

All-in pricing means
one line, not five

Surcharges, insurance, and signature fees are inside the quoted number, so a label is a single amount to book instead of a bundle to split across accounts. If a carrier reweighs the parcel afterwards, that difference arrives as its own dated entry rather than as an unexplained movement in a balance.

Shipment summary
UPS Ground $12.49
Insurance $0.75
Fuel surcharge $0.32
Total $13.56

Four carriers,
one postage account

USPS, UPS, FedEx, and DHL are quoted on the same parcel and paid from the same prepaid balance, so switching carrier order by order never splinters your chart of accounts. The account structure is decided by the flow — outbound postage, inbound freight, shipping income — not by which carrier happened to win the box.

Compare rates
UPS UPS $12.48
FedEx FedEx $13.22
DHL DHL $14.10
USPS USPS $11.79
Duties & taxes paid

Records your bookkeeper
can actually pull

Shipments and their adjustments are readable over REST for any period, with unlimited calls on every plan, so getting a quarter of history out is a script rather than an afternoon of copy-paste. There is no ready-made connector for any specific accounting package, and this page will not imply one — the API and the in-app ledger are the bridge.

POST /v1/shipments
{
"to": { "name": "Maya" },
"from": { "name": "Alex" },
"service": "ups_ground",
"label_format": "pdf"
}
Webhook delivered
GoatLabels mobile shipments queue showing one all-in amount per parcel
Billy drafting a label from a pasted order on mobile before anything posts

Purchase recorded

Postage expense · dated today

Books do not wait for the desk

The record is written where the parcel is packed.

The reason small-seller shipping books go bad is not ignorance of debits and credits — it is a gap between where the label gets bought and where anything gets written down. Closing that gap is the whole trick: buy the label from the phone at the packing table and the dated record exists before the box is taped.

Buy from the phone and the entry is already dated, referenced, and sitting in the ledger — nothing to write on a sticky note.
One all-in amount per label, so the number you would have jotted down is the number that posted.
Wallet balance visible while you pack, so a low balance is caught before a card top-up interrupts a run.
Void from the same screen and the credit lands back on the balance as its own record, not as an edit to the old one.
Every shipment keeps its own reference, so the order's true delivered cost is one lookup away later.
Ask the ledger, not the shoebox

What did that order actually cost to deliver?

The question a shipping ledger exists to answer is per-order, and it is usually asked with your hands full. Ask out loud and Billy finds the shipment, reads back what was paid and what has landed against it since, and tells you whether an adjustment has posted — so the delivered cost of one parcel is a sentence rather than a reconciliation. Included on every plan. This is the real product, not a render.

goatlabels.io/dashboard/shipments — Billy
Billy reading back a shipment's purchase and its later adjustment over the purchased labels list

Listening

"What did we pay to ship order 1024?"

Delivered · adjustment posted

Order #1024 · reweigh billed to the same shipment

Speaks plain English · finds a shipment by order or buyer · says what posted and when · included on every plan, so nothing about your records sits behind a tier.

One amount to book

Four quotes. One ledger line.

This is what makes a label a single journal entry instead of a bundle to split: each carrier comes back as one all-in number with its delivery window, and that exact amount is what leaves the prepaid balance. Figures below are invented illustration, exactly like the worked entries above — copy the shape, not the numbers.

Denver, CO → Austin, TX 1.4 lb 10×7×4 in
The amount that posts
USPS

USPS

Ground Advantage

2–5 days

$7.40

$1.20 of that figure is the insurance premium, recorded on the same shipment

all-in · one debit, one credit

UPS

UPS

Ground

3–4 days

$10.80

$1.20 of that figure is the insurance premium, recorded on the same shipment

all-in · one debit, one credit

FedEx

FedEx

Home Delivery

2–4 days

$11.40

$1.20 of that figure is the insurance premium, recorded on the same shipment

all-in · one debit, one credit

No unexplained movement in the balance Void → its own dated credit entry Multi-currency display
REST API v1 · every plan

Your books want records, not screenshots.

Every label purchase, void credit, and adjustment is its own record with its own date — readable over REST with unlimited calls on every plan, so pulling a quarter of shipping history for your accountant is a script, not an afternoon of copy-paste.

List shipments and their adjustments for any period over REST
Void credits and adjustments arrive as separate records, never silent edits
shipment.adjustment.created webhook posts corrections the day they land
OpenAPI 3.1 spec, unlimited calls — the contract lives in the docs
Read the API docs Get a free API key $0 API on every plan
curl https://api.goatlabels.io/api/v1/shipments
POST /api/v1/shipments
Authorization: Bearer sk_live_…
Idempotency-Key: ord_8421

{
  "to": { "name": "Joyce", "city": "Berlin", "country": "DE" },
  "parcel": { "weight": 2.6, "weight_unit": "lb" },
  "service": "fedex_intl_priority"
}
What the software costs your P&L

One vendor line, or none at all.

Software fees are the other half of what shipping costs you, and they book differently from postage: a subscription is a period expense whether or not a parcel moved. On Free there is no such line — the only shipping charge in your books is the postage you bought. Pro is a flat monthly plan, and if you take it, it lands as one predictable recurring expense you can budget rather than a variable you have to explain.

Pro

Most popular
$40 / month
Unlimited shipments — one flat, budgetable expense line
Cheaper label pricing, which moves postage expense rather than adding an account
Billy AI on Telegram — draft a label without opening the dashboard
API access still free and unlimited on either plan

Volume pricing

illustrative
less volume more volume

more volume → lower per-label rates

Free

$0 / forever

No software line on the profit and loss at all — just postage, dated per label.

50 shipments a month, no monthly minimum to print and no fee in a quiet month
USPS, UPS, FedEx, and DHL quoted as one all-in amount each, so one label books as one line
Void credits and carrier adjustments arrive as their own dated records, never as edits
Billy AI unlimited in the web app — paste, screenshot, or speak an order
REST API with unlimited calls, so pulling a period of history costs nothing extra

Billy is not a separate expense

The assistant that drafts a label from a pasted order and validates the address before anything posts runs unlimited on Free. It never becomes its own vendor line in your books; Pro simply adds Billy on Telegram.

Web — every plan Telegram — Pro

Exports are not a paid add-on

GET /api/v1/shipments

200 OK · plan: free

Unlimited calls on Free — the bridge to your accounting workflow costs nothing.

We'll beat your current rates

Bring your invoice — on Pro we work with you to beat the rates you're getting from

ShippoPirateShipShipStation
No contracts No monthly minimum to print Nothing to accrue in a quiet month
USPS UPS FedEx DHL

Label prices are quoted live from USPS, UPS, FedEx, and DHL as one all-in number, and that exact amount is what debits your prepaid balance — which is why the ledger entry and the receipt always agree. Full pricing details

Who needs the shipping ledger to hold up

Four sellers whose margin lives in the postage account.

The chart of accounts above is the same for all of them. What differs is which entry goes wrong first when shipping and its corrections share one line.

Sellers who charge for shipping at checkout

Shipping income vs postage expense

Two accounts, never netted

Netting what buyers paid against what postage cost feels tidy and destroys the one comparison that matters. Kept apart, the two accounts face each other on the profit and loss and say plainly whether delivery is funding itself.

2 accounts, facing each other income booked with the sale postage booked at purchase
goatlabels.io/dashboard/shipments
GoatLabels shipments ledger showing purchases, void credits, and adjustments as separate dated records

Makers who also buy inventory in

Inbound freight vs outbound postage

Carriage on stock you purchased belongs with that stock; postage on customer orders is a cost of selling. Letting the two share an account is the fastest way to a gross margin nobody can reconcile.

Two flows, two accounts

Inbound freight into inventory · outbound postage as expense

Sellers quoting from DMs

Orders with no feed still need a record

what does shipping this to Austin come to?
Bought all-in · dated entry, referenced

Anyone closing a period with corrections outstanding

Voids and adjustments land after the sale

3

kinds of entry — purchase, void credit, adjustment — each with its own date and reference

Shipping bookkeeping, answered

Is shipping a cost of goods sold or an operating expense?
Both positions are defensible, which is why sellers disagree: outbound postage on customer orders is most commonly treated as a selling or operating expense, while inbound freight on inventory you purchased belongs in the cost of that inventory. What matters more than the label is that you split the flows, pick a treatment with your accountant, and apply it consistently — switching silently mid-year is what makes margins incomparable.
How do I record shipping I charged the buyer?
As income, in its own shipping-income account — never netted against postage expense. Netting hides the number a small seller most needs to see: whether what buyers pay for delivery is covering what delivery actually costs. Book the charge with the sale, book the postage as its own expense, and let the two accounts face each other on the profit and loss.
How do I book a carrier adjustment?
Debit postage expense and credit the prepaid wallet for the adjustment amount, dated when the adjustment posted and referenced to the original shipment — and if the wallet balance could not cover it, credit the card liability for the remainder instead, because that is where the money actually came from. What an adjustment is and how to dispute one is covered on the carrier billing adjustments page.
How do I book a voided label refund?
As the mirror of the purchase: debit the prepaid wallet asset and credit postage expense for the label amount, dated when the credit posted. The credit lands back in the wallet as spendable balance rather than crawling back to a card, which is also why it books so cleanly — the how and when of voiding itself lives on the void a shipping label page.
How do I get my shipping history into accounting software?
Over the REST API, which exposes shipments and their adjustments as records your bookkeeper's tooling — or a short script — can pull for any period, with calls unlimited on every plan. GoatLabels does not claim a ready-made connector for any specific accounting package; the API and the in-app ledger are the bridge, and the current endpoints live in the API docs.
Real sellers, real words

Sellers who can say what a parcel actually cost them.

A video took off and I had 80 TikTok Shop orders by morning. I printed every label from my phone on the bus to the post office.
E

Early customer · TikTok

TikTok Shop seller

TikTok Shop
I run my Etsy shop from the kitchen. The AI reads the order, picks the carrier, the label prints. That's the whole workflow now.
E

Early customer · Etsy

Etsy maker

Etsy
The API is what every shipping API pretends to be. Idempotency that actually works.
S

Sasha R.

Staff engineer, marketplace

API user
One ledger line per label. Corrections dated and referenced.

Books that match the mailroom.
Down to the last adjustment.

All-in prices make one-line entries, voids and adjustments post as their own dated records, and the API hands your bookkeeper the period's history on request.

Sign up in seconds. No card required. No monthly minimum to print.