# Freight Fuel Surcharge Check (`wheresprada/freight-fuel-surcharge-check`) Actor

Check shipment fuel charges against supplied dated percentage schedules and explicit eligible charge components. Flag wrong-week gaps, calculation differences and unresolved contract inputs. No carrier login, claims or assumed overcharges.

- **URL**: https://apify.com/wheresprada/freight-fuel-surcharge-check.md
- **Developed by:** [Mahruf Hossain](https://apify.com/wheresprada) (community)
- **Categories:** Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.45 / completed fuel surcharge review

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Freight Fuel Surcharge Check

Review fuel charges against the right dated percentage and the right charge base. This Actor compares shipment-level fuel amounts with supplied rate schedules, includes only explicitly fuel-eligible components, and returns calculation differences with the rate reference behind them.

For shipping finance teams and freight bookkeepers, it provides a repeatable second check before investigating a carrier bill. It does not infer contract terms, retrieve live tariffs, contact carriers or promise recoveries. An unresolved shipment remains unresolved rather than receiving an assumed zero rate or a false match.

### Who should use it?

Use this when you already have structured shipment charges and an authorized percentage-based fuel schedule. Suitable users include e-commerce shipping teams reviewing parcel invoices, freight bookkeepers checking weekly exports, and logistics analysts building a pre-payment review workflow.

It is not a full freight-audit service. If you need PDF interpretation, freight-class analysis, carrier disputes or contract negotiation, use an appropriate broader service. This Actor focuses on a specific calculation that can be repeated across a bounded batch without changing your existing systems.

### Key features

- Matches carrier, service, contract date basis and inclusive effective-date interval.
- Uses explicitly classified charge components, so nonfuel charges do not automatically inflate the base.
- Applies a percentage once to the summed eligible base using integer arithmetic and half-up cent rounding.
- Preserves signed differences: billed above and billed below calculation are distinct.
- Flags missing dated rates and unconfirmed contract rules as unresolved.
- Keeps unresolved shipments visible and excludes them explicitly from compared totals.
- Rejects overlapping rate intervals and contradictory duplicate IDs instead of choosing arbitrarily.
- Reviews up to 2,000 shipments and 500 dated schedule rows per report.

### Practical examples

A merchant can check whether a new weekly export used the selected fuel percentage for each shipment date. A bookkeeper can see whether an accessorial was included in the declared fuel base. A logistics analyst can review invoice-date-based and shipment-date-based contracts separately without silently mixing them. An automation developer can route unresolved shipments to a human instead of treating incomplete inputs as approved bills.

These are potential workflows, not claims about errors at any particular carrier or customer. Published carrier schedules are evidence that rates vary; the actual contract determines which rules apply to your account.

### Quick start

1. Identify your contractual percentage-based fuel model, eligible components, date basis and rounding rule.
2. Supply the applicable dated rates and a stable source reference for each. Rates are not downloaded by this Actor.
3. Supply shipment charges with explicit `fuelEligible` flags. Exclude the fuel surcharge itself from the calculation base.
4. Set `basisConfirmed` and `componentsComplete` truthfully. Use false when the contract or component coverage is unresolved.
5. Run the Actor and review `findings` together with `unresolved`, not just the net total.

Only use the comparison where the contractual model is a percentage applied once to the eligible shipment base, rounded half-up to cents. Other rounding or fuel models are outside scope.

The prefilled example is invented data with one deliberate difference. A completed demonstration is billable.

### Input example

```json
{
  "currency": "USD",
  "rateRows": [{
    "id": "R-DEMO",
    "carrier": "CARRIER-DEMO",
    "service": "GROUND",
    "validFrom": "2026-10-05",
    "validThrough": "2026-10-11",
    "percent": "30.25",
    "dateBasis": "shipmentDate",
    "sourceUrl": "https://example.org/fuel-rates"
  }],
  "shipments": [{
    "id": "S-DEMO",
    "carrier": "CARRIER-DEMO",
    "service": "GROUND",
    "shipmentDate": "2026-10-09",
    "invoiceDate": "2026-10-12",
    "dateBasis": "shipmentDate",
    "basisConfirmed": true,
    "componentsComplete": true,
    "components": [
      {"id": "TRANSPORT", "amount": "100.00", "fuelEligible": true},
      {"id": "OTHER", "amount": "20.00", "fuelEligible": false}
    ],
    "billedFuel": "36.30"
  }]
}
```

`CARRIER-DEMO` and `example.org` are fictional demonstration references. The percentage is an illustrative input, not a current carrier quote or a contract entitlement.

### Input parameters

| Input | Required | Rules |
|---|---|---|
| `currency` | Yes | One shared two-decimal currency: USD, CAD, EUR, GBP or AUD. |
| `rateRows` | Yes | 1–500 schedule rows. No overlapping validity intervals for the same carrier/service/date basis. |
| `shipments` | Yes | 1–2,000 shipment records, each containing 1–30 charge components. |

Each rate row requires `id`, `carrier`, `service`, `validFrom`, `validThrough`, `percent`, `dateBasis` and `sourceUrl`. Dates must be real `YYYY-MM-DD` dates. Rate percentages are nonnegative decimal strings between 0 and 100, with at most four decimal places. Date basis is exactly `shipmentDate` or `invoiceDate`. Source URLs must be HTTPS without embedded credentials, query strings or fragments. The URL is a retained reference, not a fetched or authenticated source.

Each shipment requires `id`, `carrier`, `service`, both dates, `dateBasis`, `basisConfirmed`, `componentsComplete`, `components` and `billedFuel`. Confirm the base, date and supported rounding rules before setting `basisConfirmed` true. `componentsComplete` declares full component coverage for this review; it is not independently verified.

Each component has a unique `id`, nonnegative `amount` string with at most two decimal places, and boolean `fuelEligible`. Do not include the fuel charge itself as an eligible component. Supply the actual contractual net base after relevant discounts; the Actor does not apply discounts or determine eligibility automatically. Credits, returns, negative adjustments, minimum/maximum fuel charges and cents-per-mile models are unsupported.

IDs, carrier and service labels use 1–60 letters, numbers, periods, underscores or hyphens and are normalized to uppercase. Different representations of the same carrier should be mapped consistently before review. Do not use account numbers or personal information as IDs.

### Output example

Selected fields from the verified result for the exact input above:

```json
{
  "currency": "USD",
  "summary": {
    "uniqueShipmentCount": 1,
    "comparedShipments": 1,
    "unresolvedShipments": 0,
    "identicalDuplicatesIgnored": 0,
    "rateCount": 1,
    "findingCount": 1,
    "comparedBilledFuel": "36.30",
    "comparedExpectedFuel": "30.25",
    "signedComparedDifference": "6.05"
  },
  "reviewRequired": true
}
```

The full report includes `rows`, `findings`, `unresolved`, supplied `rateRows`, a check timestamp, an input fingerprint, coverage statements and the rounding model.

| Output | Meaning |
|---|---|
| `rows[].eligibleBase` | Sum of explicitly eligible component amounts. |
| `rows[].expectedFuel` | Calculated value, or null when inputs do not establish a comparison. |
| `rows[].difference` | Billed minus calculated fuel, or null for unresolved rows. |
| `findings` | Nonzero calculation differences with shipment, rate ID and review action. |
| `unresolved` | Every shipment held for missing rules, incomplete components or unavailable dated rates. |
| `summary` | Counts and totals for compared shipments only; unresolved amounts are excluded explicitly. |
| `coverage` | Rates and contractual rules were not independently verified. |

A signed total can hide offsetting differences. Inspect individual findings rather than interpreting a zero combined difference as no issues.

### How it works

The Actor validates the entire input before producing output. It groups rates by carrier, service and date basis, rejects overlapping intervals, and selects the applicable interval for each shipment. It sums eligible component cents, applies the percentage once, then rounds half-up to the nearest cent. It compares that result with the supplied fuel charge.

Identical records under the same ID are counted and ignored. Conflicting uses of an ID fail. Equal amounts under different shipment IDs remain separate shipments. Missing contract confirmation, incomplete component coverage or a date without an applicable rate produce explicit unresolved rows. No rate is carried forward beyond its stated interval.

### Pricing

Configured launch price: **$0.45 per completed report**, including up to 2,000 shipments and 500 rate rows. A report is one dataset item and one `fuel-surcharge-review` event. Reports containing differences or unresolved shipments are completed review work and are billable. Invalid input rejected before report creation does not trigger the event.

Actor event examples: one report $0.45; ten reports $4.50; 100 reports $45.00. Four weekly reviews cost $1.80 in Actor events. These examples do not establish customer savings. Applicable Apify plan/platform charges, retained storage and downstream access are separate; the Store pricing panel is authoritative. No contingency fee, per-finding fee or recovered-money percentage applies.

### API and scheduling

Use the official Apify client to send a refreshed export:

```javascript
import { ApifyClient } from 'apify-client';
import fs from 'node:fs';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const input = JSON.parse(fs.readFileSync('sample_input.json', 'utf8'));
const run = await client.actor('wheresprada/freight-fuel-surcharge-check').call(input);
const { value } = await client.keyValueStore(run.defaultKeyValueStoreId).getRecord('OUTPUT');
console.log(value.summary, value.unresolved);
```

Install `apify-client` in your integration and save the tested JSON as `sample_input.json`. Keep API tokens in secure environment storage. A scheduled task can run after your authorized export workflow refreshes its input. Repeating an old snapshot does not fetch new rates or invoices. Completion webhooks can notify a downstream review queue; inspect the actual run status and unresolved records first.

### Limits and accuracy

Input is capped at 2,000,000 UTF-8 bytes, with 128 MB memory and a 30-second runtime limit. Oversized requests fail without silently truncating shipments. This version supports only positive percentage-based models with the documented rounding rule and one shared currency. It does not verify tariff applicability, account-specific discounts, taxes, freight classification, weights, legal entitlement or recoverability.

A calculation difference is a review candidate, not a confirmed carrier error. Contract amendments, rounding, eligibility or date-basis mistakes in the supplied input may explain it. Rates and rules must be maintained by an authorized user or upstream process.

### Privacy and security

No carrier login, proxies, paid external API or network retrieval is required by processing. Avoid uploading names, addresses, account numbers, credentials or entire commercial invoices. The provided inputs and resulting reports are held in Apify run storage according to its access and retention settings. No automatic deletion or security certification is promised. Source references and commercial amounts may be sensitive even without personal information; restrict their dataset links appropriately.

### Troubleshooting and FAQ

**Why is a shipment unresolved?** Check its reason codes. Confirm the contract model, complete charge components and a matching dated rate. Unknown values are not treated as zero.

**Why is my rate schedule rejected?** Two intervals overlap for the same carrier, service and date basis, or an ID has conflicting records. Resolve those ambiguities first.

**Can it download current carrier rates?** No. Supply the applicable schedule from an authorized source. Published rates may not match your account contract.

**Can I use cents per mile?** No. This product checks percentage-based fuel models only.

**Does a difference prove an overcharge?** No. Review the contract and source records. The Actor performs calculations, not legal or commercial claims decisions.

**Is an unresolved report charged?** Yes, when a complete report was produced. Its explicit holds are the useful result. Invalid input does not trigger the report event.

**Where are results?** One complete report appears in the default dataset and under `OUTPUT` in the key-value store.

### Support and source context

Report reproducible problems through this Actor's Apify Issues tab with a run ID and a redacted minimal example. Do not post invoices, account details or tokens publicly.

Carrier context: [UPS fuel surcharges and effective-date history](https://www.ups.com/us/en/support/shipping-support/shipping-costs-rates/fuel-surcharges). Different services and contracts can use different rules. The Actor is independent and not affiliated with any carrier. Platform integration guidance is in the [Apify documentation](https://docs.apify.com/platform).

# Actor input Schema

## `currency` (type: `string`):

One two-decimal currency for every amount. No FX conversion.

## `rateRows` (type: `array`):

1-500 rate rows: id, carrier, service, validFrom, validThrough (inclusive YYYY-MM-DD), percent (0-100 decimal string, at most 4 places), dateBasis (shipmentDate or invoiceDate), sourceUrl (HTTPS without query tokens). Resolve overlapping intervals first.

## `shipments` (type: `array`):

1-2000 shipments: id, carrier, service, shipmentDate, invoiceDate, dateBasis, basisConfirmed, componentsComplete, components \[{id,amount,fuelEligible}], billedFuel. Amounts are nonnegative strings with at most 2 decimals. No credits, cents-per-mile models or automatic eligibility decisions.

## Actor input object example

```json
{
  "currency": "USD",
  "rateRows": [
    {
      "id": "R-DEMO",
      "carrier": "CARRIER-DEMO",
      "service": "GROUND",
      "validFrom": "2026-10-05",
      "validThrough": "2026-10-11",
      "percent": "30.25",
      "dateBasis": "shipmentDate",
      "sourceUrl": "https://example.org/fuel-rates"
    }
  ],
  "shipments": [
    {
      "id": "S-DEMO",
      "carrier": "CARRIER-DEMO",
      "service": "GROUND",
      "shipmentDate": "2026-10-09",
      "invoiceDate": "2026-10-12",
      "dateBasis": "shipmentDate",
      "basisConfirmed": true,
      "componentsComplete": true,
      "components": [
        {
          "id": "TRANSPORT",
          "amount": "100.00",
          "fuelEligible": true
        },
        {
          "id": "OTHER",
          "amount": "20.00",
          "fuelEligible": false
        }
      ],
      "billedFuel": "36.30"
    }
  ]
}
```

# Actor output Schema

## `report` (type: `string`):

No description

## `reports` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "currency": "USD",
    "rateRows": [
        {
            "id": "R-DEMO",
            "carrier": "CARRIER-DEMO",
            "service": "GROUND",
            "validFrom": "2026-10-05",
            "validThrough": "2026-10-11",
            "percent": "30.25",
            "dateBasis": "shipmentDate",
            "sourceUrl": "https://example.org/fuel-rates"
        }
    ],
    "shipments": [
        {
            "id": "S-DEMO",
            "carrier": "CARRIER-DEMO",
            "service": "GROUND",
            "shipmentDate": "2026-10-09",
            "invoiceDate": "2026-10-12",
            "dateBasis": "shipmentDate",
            "basisConfirmed": true,
            "componentsComplete": true,
            "components": [
                {
                    "id": "TRANSPORT",
                    "amount": "100.00",
                    "fuelEligible": true
                },
                {
                    "id": "OTHER",
                    "amount": "20.00",
                    "fuelEligible": false
                }
            ],
            "billedFuel": "36.30"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("wheresprada/freight-fuel-surcharge-check").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "currency": "USD",
    "rateRows": [{
            "id": "R-DEMO",
            "carrier": "CARRIER-DEMO",
            "service": "GROUND",
            "validFrom": "2026-10-05",
            "validThrough": "2026-10-11",
            "percent": "30.25",
            "dateBasis": "shipmentDate",
            "sourceUrl": "https://example.org/fuel-rates",
        }],
    "shipments": [{
            "id": "S-DEMO",
            "carrier": "CARRIER-DEMO",
            "service": "GROUND",
            "shipmentDate": "2026-10-09",
            "invoiceDate": "2026-10-12",
            "dateBasis": "shipmentDate",
            "basisConfirmed": True,
            "componentsComplete": True,
            "components": [
                {
                    "id": "TRANSPORT",
                    "amount": "100.00",
                    "fuelEligible": True,
                },
                {
                    "id": "OTHER",
                    "amount": "20.00",
                    "fuelEligible": False,
                },
            ],
            "billedFuel": "36.30",
        }],
}

# Run the Actor and wait for it to finish
run = client.actor("wheresprada/freight-fuel-surcharge-check").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "currency": "USD",
  "rateRows": [
    {
      "id": "R-DEMO",
      "carrier": "CARRIER-DEMO",
      "service": "GROUND",
      "validFrom": "2026-10-05",
      "validThrough": "2026-10-11",
      "percent": "30.25",
      "dateBasis": "shipmentDate",
      "sourceUrl": "https://example.org/fuel-rates"
    }
  ],
  "shipments": [
    {
      "id": "S-DEMO",
      "carrier": "CARRIER-DEMO",
      "service": "GROUND",
      "shipmentDate": "2026-10-09",
      "invoiceDate": "2026-10-12",
      "dateBasis": "shipmentDate",
      "basisConfirmed": true,
      "componentsComplete": true,
      "components": [
        {
          "id": "TRANSPORT",
          "amount": "100.00",
          "fuelEligible": true
        },
        {
          "id": "OTHER",
          "amount": "20.00",
          "fuelEligible": false
        }
      ],
      "billedFuel": "36.30"
    }
  ]
}' |
apify call wheresprada/freight-fuel-surcharge-check --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,wheresprada/freight-fuel-surcharge-check"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Zhu4yUDmkWoWqJcoP/builds/wBe4b6ddDlRmbgEaR/openapi.json
