3PL Hourly Labor Rates You Cannot Compare

By Wayan Sunnasy Published 2026-08-17 Data last verified 2026-08-04 5 sources How we verify →

Somewhere on your quote is a line that reads $48 an hour, and there is no way to turn it into a cost per order. Multiplying it by your volume does nothing, because the missing quantity is hours, and hours is the one thing the card does not print. Below is every hourly rate we could source, followed by the reason we will not convert them for you.

Hourly labor turns up on every hidden-fee list written for this query. It is not hidden. Flexport, Simple Global and Fulfyld publish their hourly rates on public pages, and we have copied them here with the wording they used and the dates we read them. What makes the line unshoppable is not secrecy. It is that an hourly rate is a different kind of object from a per-order fee, and the conversion between them needs an hours estimate that none of the three published on the pages we read, and that we decline to invent.

What does a 3PL charge per hour?

Flexport, Simple Global and Fulfyld are the companies in our dataset that publish an hourly figure. Flexport’s is $48 an hour on every service it prices by the hour. Fulfyld’s is $40, once on a row whose unit reads per hour and once on a row whose unit reads per man-hour, a difference this page comes back to. Simple Global’s is “from $38” for basic work orders and “from $48” for complex ones. Every other company we track either publishes no hourly rate on the pages we read, or publishes no dollar figure at all, and those are two different facts that we keep apart throughout.

We maintain a dataset of 241 sourced fee rows across 23 fulfillment operations. Filter it on rows whose unit contains the word hour and you get the table below, and nothing else.

Every published hourly rate we could source

Ordered by company, then by the unit string exactly as our dataset records it. Read the last three columns before you read the amount.

CompanyFee, as the card labels itAmount (USD)Unit, verbatimWhere it sits in our dataConditions on the rowRead
Flexportinventory inspection48per hourreceivingvendor warning: not comparable to a per-order or per-unit fee without an hours assumption2026-08-12
Flexportrush receive / shipping48per hourreceivingminimum 4 hours; plus the same vendor warning2026-08-12
Flexportcycle count48per houraccount managementinventory count at merchant request; plus the same warning2026-08-12
Flexportrestocking after cancellation48per hourpick and packcharged when an order is cancelled after being picked; plus the same warning2026-08-12
Simple Globalbasic work order labor“from $38”per hourkittingoptional add-on service2026-08-04
Simple Globalcomplex work order labor“from $48”per hourkittingoptional add-on service2026-08-04
Simple Globalinventory audit and reporting labor“from $48”per houraccount managementoptional add-on service2026-08-04
Fulfyldreceiving labor after free onboarding40per hourreceivingfirst 2 hours of onboarding receiving are free2026-08-04
Fulfyldspecial projects labor40per man-hourkittingnone recorded on the row2026-08-04

The first thing to read is the fifth column. Flexport’s single $48 rate appears under receiving, under account management and under pick and pack. Simple Global’s appear under kitting and under account management. Fulfyld’s appear under receiving and under kitting. An hourly rate is not a fee category. It is a billing shape that cuts across categories, which is why it turns up inside a receiving comparison, inside a pick-and-pack comparison and inside an account-management comparison, and converts to the denominator of none of them.

The second thing is that these rates compare cleanly to one thing only, and then only where the unit strings match: each other. Flexport’s $48 is 20% above Fulfyld’s $40 receiving rate ($48 ÷ $40 = 1.2, our arithmetic). That is a real, checkable comparison, because both of those rows read per hour. The moment you set either against a per-order or per-pallet fee, you are the one supplying the hours.

Why an hourly rate resists normalization

Every other fee shape in our dataset carries its own quantity. A per-order fee multiplies by orders, which you know. A per-cubic-foot rate multiplies by cube, which you can measure. A per-pallet fee multiplies by pallets, which appear on a packing list. Our comparison method works because those quantities come off your own order profile.

An hourly rate multiplies by hours of somebody else’s labor in somebody else’s building. That quantity does not exist anywhere on your side of the transaction. It is produced by the warehouse after the work is done, and no row in our dataset records a standard for it: not minutes per unit inspected, not units counted per hour, not a typical duration for any task in the table above.

Flexport says this in its own terms, and we recorded the sentence verbatim in the conditions field of every one of its hourly rows, British spelling and capitals included:

labour rate, NOT comparable to a per-order or per-unit fee without an hours assumption - do not average into a per-order comparison

That is the whole argument, and it is the vendor’s rather than ours. We keep it in the data because it is a condition on the row, in the same way that “minimum 4 hours” is a condition on the row.

The four-hour minimum, and what it costs before anything happens

The only row in that table with a stated minimum is Flexport’s rush receive / shipping line: $48 per hour with a minimum 4 hours, read 2026-08-12. Four hours at $48 is $192, our arithmetic, and that is the smallest charge the line can produce whether the work takes four hours or twenty minutes.

Set it against the per-event fees on the same card. Flexport publishes floor-loaded container unloading at $650 per container for a 40-foot box and $325 for a 20-foot, both read 2026-08-12. So one rush-receive minimum is about 59% of a 20-foot container unload ($192 ÷ $325, our arithmetic) before a single carton has been counted. Neither figure is concealed. Both are on the same public page. They are simply not the same kind of number, and only one of them can be estimated in advance.

Flexport publishes a second floor on the same page that is not hourly at all: a $200 prep job minimum, unit per job, read 2026-08-04. Our rows do not record whether it attaches to any of the hourly lines above, so we do not stack the two figures. It is here because a vendor can put a floor under labor in more than one shape, and a reader asking about minimums should ask about both.

Back to the four-hour floor, which decides short jobs, and short jobs are where an hourly comparison usually stops mattering. Hour for hour, Fulfyld’s $40 receiving labor is cheaper than Flexport’s $48, and the four-hour floor widens that gap at the short end rather than closing it: a one-hour job is $40 on Fulfyld’s row and $192 on Flexport’s rush receive line, our arithmetic on both. Neither of those two rows can reverse the order. What could is outside them: a minimum on Fulfyld’s side that our row does not record, which is a limit on our sourcing and not a finding that none exists, and crew size, which the per man-hour string on Fulfyld’s other row shows is a live question. So we will say which rate is lower per hour, because both rows carry the same unit. We will not say which produces the smaller invoice, because that needs hours and headcount neither card prints.

Stop normalizing quotes by hand. The 3PL Quote Normalizer Kit takes your order profile plus up to 5 competing rate cards and returns true all-in cost per order, a 12-month projection, and breakeven volumes, plus the RFP template and 40-point contract red-flag checklist. Get the Kit →

“From $38” is not a rate either

Simple Global’s rows carry a qualifier rather than a price. It publishes basic work order labor at “from $38” per hour, and complex work order labor and inventory audit and reporting labor at “from $48” per hour, all read 2026-08-04. Those are floors. They tell you where the number starts and nothing about where it stops, and there is no second figure on the row to bracket them against.

The distance between the two floors is worth reading on its own: the complex floor is 26% above the basic floor ($48 ÷ $38 = 1.26, our arithmetic). Our rows record no definition of which jobs count as basic and which as complex, only optional add-on service. So the reader is asked to price work of unknown duration, at a rate with no ceiling on the row, sorted into a category whose boundary our rows do not record.

That same page is why we also hold a quote-gated row for Simple Global. Its conditions field records that setup fee, packaging, order minimums, kitting flat rate, returns fee and account management fee are not published on the pricing page beyond those hourly rates, read 2026-08-04. The hourly figures are not one disclosure among many on that card. For value-added work they are the disclosure, and each of them is a floor.

Our comparison workbook brackets figures like these rather than picking a midpoint, because a midpoint between $38 and an unpublished ceiling is not a number, it is a preference.

“Per hour” and “per man-hour” are not the same unit

The unit strings in the table are not identical. Fulfyld’s special projects labor reads per man-hour; every other row reads per hour. Fulfyld publishes both, on the same card, at the same $40, read 2026-08-04. Same vendor, same amount, one word of difference in the unit.

That word is a multiplier. Read as per man-hour, three people working two hours is six billable hours, which at $40 is $240. Read as elapsed hours, the same job is two hours, or $80. Both figures are ours and illustrative, built from the published $40 and a crew size we made up, which is exactly the sort of invention this page exists to refuse. No row in our dataset states a crew size, and none states whether a plain per hour line is billed per worker or per clock hour.

We record the two unit strings separately rather than folding them together, because folding them would assert an equivalence the sources do not support. It is also the smallest available illustration of the general problem: a normalization pipeline that treated per hour and per man-hour as one column would be silently wrong by whatever the crew size turns out to be.

Who publishes nothing here, and who has no row at all

Three states, kept apart on purpose.

Published. Flexport, Simple Global and Fulfyld, in the table above.

Checked, and nothing published. Ten of the 23 fulfillment operations we track publish no dollar figure anywhere in our dataset, on the pages we read on the dates recorded, so we cannot say what they charge per hour any more than we can say what they charge per order. They are listed with sources in our hidden fees guide. Separately, ShipBob lists a kitting and bundling service on its pricing page as available at additional cost and attaches no amount to it, read 2026-08-04. We hold that as a quote-gated row and its unit is recorded as per unit, not per hour, so it is not evidence that ShipBob bills that work by time.

No row at all. Every remaining company has no hourly row in our dataset. That is not silence and we do not report it as silence. For the marketplace programs the gap looks structural: every row we hold for Amazon FBA, Amazon MCF and Walmart WFS carries a unit string from this list, reproduced verbatim from the column: per unit, per cubic foot per month, per lb, percent of fulfillment fee, percent of outbound fulfillment fee. Not one of them reads per hour. For everyone else it means only that we found no published hourly rate on the page we read, which is a limit on our sourcing rather than a finding about the vendor. Our methodology sets out how the three states are recorded.

Where our rows land against the number everyone quotes

This is the check only a sourced dataset can run, so we will run it plainly.

The industry figure repeated across comparison pages for warehouse receiving labor is a range of $30 to $60 an hour with an average near $39.88. It is a third-party survey number. We carry it in our hidden fees guide and in our comparison method guide, where it is attributed to Fulfill.com. It is not a dataset row and no vendor published it.

The rows in our dataset with a receiving service line and an hourly unit are Fulfyld’s receiving labor at $40 and Flexport’s inventory inspection and rush receive lines, both at $48. Every one of those amounts sits inside the $30 to $60 range, and Flexport’s is 20% above the $39.88 average ($48 ÷ $39.88 = 1.20, our arithmetic).

Our hidden fees guide summarizes the labor figure in its receiving row as $38 to $40 an hour. The Flexport hourly rows were read 2026-08-12 and added to the dataset on 2026-08-14, after that guide was written, and they put a published $48 receiving-labor rate in the data. With them in, the top of our published receiving-labor span is $48, not $40.

So the survey range holds, Flexport’s published receiving rate sits 20% above the survey average, and our own earlier summary needed the newer rows to be complete. None of that is a reason to average anything. It is a reason to quote the row and the date rather than the range.

Why we keep these rows and refuse to average them

There is a decent argument for dropping hourly lines out of a per-unit fee dataset altogether, on the grounds that a column of unconvertible numbers pollutes every aggregate computed over it. We keep them, and we compute no aggregate over them.

The reason is that the fee is real and it lands on real invoices. A brand that never sees an hourly line on a quote will still see one on a bill, for a cycle count it requested, a rush receive it needed, or an order it cancelled after picking. Removing the rows would make the dataset tidier and the reader less prepared. What we can do instead is publish them with the unit intact, with the vendor’s own warning attached where the vendor supplied one, and never let them into a per-order average. That refusal is the one described on our methodology page: a figure we cannot source is a figure we do not print.

What to ask so an hourly line becomes comparable

  1. Ask what a billable hour is. Per worker or per clock hour. Fulfyld publishes both per hour and per man-hour on one card at the same $40, so the distinction is real enough that a vendor writes it two ways.
  2. Ask for the minimum in writing, separately from the rate. Flexport publishes a four-hour minimum on rush receive, which makes the smallest charge on that line $192. Ask every vendor whether each hourly service carries one, and in what increments time is rounded once the minimum is met.
  3. Ask who starts and stops the clock, and whether travel, setup and teardown sit inside it. No row in our dataset records an answer.
  4. Ask for a duration estimate on the two jobs you will actually buy. Not a rate. An estimate in hours for a 500-unit inspection, or for a full cycle count, in writing. That estimate is the number that converts the rate, and once a vendor has given it to you, you can normalize it yourself and hold them to it.
  5. Ask for the ceiling on anything published as “from $X”. Simple Global’s basic and complex floors are 26% apart and our rows record no definition of either kind of work, so the definition matters as much as the ceiling.
  6. Put the answers in the contract, not the quote. Our contract red flags list covers what happens when a rate is agreed and its measurement is not. Every row on this page is browsable with its source at /data/3pl-fee-benchmarks/#receiving and the neighboring service-line sections.

Limitations, stated

This is 23 fulfillment operations, not the market, and three of them (Amazon FBA, Amazon MCF and Walmart WFS) are marketplace programs rather than 3PLs. It is US-focused. The bulk of the dataset was collected 2026-08-04; the Flexport hourly and container rows here were read directly in a browser on 2026-08-12, because that page needs one, and were added to the dataset on 2026-08-14. Every other row on this page, Flexport’s prep job minimum included, keeps its 2026-08-04 read date and has not been individually re-read since.

We publish no total for the hourly rows, deliberately, and the reason belongs on this page more than on any other. Every hand-typed count on this site is registered against a predicate in our figure-check script that has to reproduce it, and no predicate we expose can reproduce a count filtered on the unit column. A number nobody can recompute is exactly the kind of number this page is about declining to print, so the rows are enumerated in full instead, the filter that produces them is printed above the table, and the vendors are named rather than counted. Count them yourself if you want the total. We will not print one we cannot check.

Two related absences. We hold no hourly row for any company but the ones named here, which is a limit on what we have sourced and not a finding that nobody else bills by time. And we hold no duration, crew size or throughput figure for any task in the table, from any vendor, which is why there is no worked example on this page converting an hourly rate into a cost per order. Vendors change prices without notice. If a figure here no longer matches its source, email data@ratecardlab.com and we will publish the correction.

Figures are quoted from the vendor’s own page on the date given and cross-checked against our dataset. The unit column is reproduced verbatim, including the place where a single card’s unit strings do not match each other. Where we do arithmetic on a published figure rather than reporting it, the sentence says so.

Sources

The providers named above, fee by fee

This guide spans more than one fee category, so rather than a partial list: here is every provider it names that publishes enough of a rate card to have a page, with every figure sourced and dated.

  • Flexport 75 published fees across 13 categories
  • Amazon MCF 31 published fees across 2 categories
  • Walmart WFS 26 published fees across 5 categories
  • Fulfyld 12 published fees across 5 categories
  • Simple Global 8 published fees across 5 categories

All published fees by vendor · What a 3PL costs in 2026

When a figure on this page changes

We re-check these rates against the vendor's own page and publish every correction. Leave an address and you get an email when a number in this guide moves or a company is added — nothing else, and nothing on a schedule. To come off, email data@ratecardlab.com and we delete the record.