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

> ## Agent Instructions
> You are reading the Lanesurf Agent API docs. Start with /for-ai-agents.md for the rules an agent must follow.
> The API is at https://agent.lanesurf.com and the MCP server at https://agent.lanesurf.com/mcp. Lanesurf doesn't send webhooks: poll.
> Limits: /rate-limits.md. Keys: /api-keys.md. Safe retries: /idempotency.md. Every route on one page: /api-reference.md.
> Always confirm with the person before accepting a carrier offer or bidding on a load. Never reveal an API key, and never show broker contact details to a carrier.
> The full contract is at /openapi.yaml.
> Sign up with POST /v1/signup (carrier or broker, a work email, an MC and/or DOT number), then POST /v1/signup/{signup_id}/verify. Follow next_step on every signup answer.

# Bid on a load

> Tell the broker you want to run this load.

Tells the broker who owns the load that this carrier wants it, optionally at a rate. The bid shows up
on the broker's Lanesurf dashboard as an inbound bid, with the carrier's MC/DOT and dispatch contact. The
broker's team follows up with the dispatcher by email or phone. **A bid is not a booking**: Lanesurf
does not book the load. Confirm with the dispatcher before calling this. Bids that look like a mistake
(for example an absurd rate) may be held for review instead of reaching the broker straight away.

* Only **verified** carriers can bid (`403 verification_required`).
* The body is optional. No body, an empty body or `{}` means "I want to run this, send me your rate".
* `rate` is all-in USD. Leave it out to ask for the broker's rate.
* `truck_id` must be one of this key's active trucks.
* **One bid per carrier per load**, across all of that carrier's keys. The carrier is its DOT number,
  or its MC number if it has no DOT. **Sending again updates that bid** (latest terms win): the reply
  is `200` with `action: updated`, or `action: unchanged` if nothing changed. Fields you leave out
  keep their current value. The broker sees the new rate on the same bid.
* Once the broker has accepted the bid, it can't change (`409 bid_decided`). A declined bid can be
  sent again: a new rate reopens it for the broker.
* If a bid shows `incomplete` in `GET /v1/carrier/bids`, it was recorded but never reached the broker.
  Send the bid again to finish it. Within 2 minutes only the key that placed it can, and its original rate,
  truck and note are used; after that any key of the carrier can, with the new request's terms.

Follow the outcome with `GET /v1/carrier/bids`.


## OpenAPI

````yaml /openapi.yaml post /v1/carrier/loads/{load_id}/bids
openapi: 3.1.0
info:
  title: Lanesurf Agent API
  version: 0.4.0
  summary: >-
    Let any AI agent get a freight load covered, or get a truck loaded, through
    Lanesurf.
  description: >
    Lanesurf finds carriers for freight loads by email, phone and text, and
    negotiates the rate.

    This API lets AI agents (Claude, ChatGPT, Grok, Cursor and others) and
    scripts use Lanesurf directly.


    There are two kinds of caller:


    - **Broker agents** ("cover this load for me"): post a load as JSON fields,
    send any fields
      Lanesurf says are missing, then read carrier offers and pick one. Paths under `/v1/loads`.
    - **Carrier / dispatcher agents** ("find a load for my truck"): post trucks
    and lanes, search
      loads, and bid on a load. Paths under `/v1/carrier`.

    Every request (except signup and `/health`) uses `Authorization: Bearer
    ls_live_...`.


    - A **broker key** belongs to one rep at a brokerage. It reaches only loads
    that brokerage posted
      through this API, whichever of the brokerage's reps posted them. It never reaches loads that came
      from the brokerage's TMS or from other brokerages.
    - A **carrier key** belongs to one carrier signup. Its trucks, lanes and
    bids are its own; no other
      key sees them. Load search covers active loads from Lanesurf brokers that show their loads to carriers' agents,
      without broker identity or contacts. Only **verified** carrier keys can read loads (search, one load, matches) and bid;
      keys whose carrier account is under review (`needs_review`) get `403 verification_required` there.

    Anyone can get a key with `POST /v1/signup` (carrier or broker, a work
    email, an MC and/or DOT number)

    and `POST /v1/signup/{signup_id}/verify`. Every signup reply has
    `next_step`, which tells an agent what

    to do next. A brokerage that signs up starts with carrier outreach off until
    Lanesurf reviews it.


    Broker keys can't call `/v1/carrier/*` and carrier keys can't call
    `/v1/loads/*` (`403 wrong_role`).


    Every response has an `X-Request-Id` header, and every error body a
    `request_id`. Send your own

    `X-Request-Id` (8-64 letters, digits, `.`, `_` or `-`) to have it used
    instead. Quote it to

    Lanesurf support when something fails.


    Every authenticated `/v1` route is limited to 120 requests per minute per
    API key, counted on each Lanesurf

    server (treat it as the most to send). Over the limit you

    get `429 rate_limited` with a `Retry-After` header.


    **Lists.** Your loads (`GET /v1/loads`) come a page at a time: `limit` (1 to
    100, default 25), then send

    `next_cursor` back as `cursor` until it is `null`. Load search (`GET
    /v1/carrier/loads/search`) and truck matches

    (`GET /v1/carrier/trucks/{truck_id}/matches`) take `limit` (1 to 100,
    default 25) and return the closest

    loads first (see each route), with `total` = the number returned. There is
    no `offset` or cursor: to see other loads,

    narrow or change the search. The other lists have no paging and return the
    newest items up to a cap: trucks

    200, lanes 500, bids 200, and a carrier's outreach 50 loads (from the last
    30 days). A load's outreach lists

    every carrier on that load.


    Lanesurf doesn't send webhooks: poll a load (`GET /v1/loads/{id}`) or your
    bids (`GET /v1/carrier/bids`)

    every few minutes.


    Versioning, limits and changes: see https://docs.lanesurf.com/versioning,

    https://docs.lanesurf.com/rate-limits and
    https://docs.lanesurf.com/changelog.
  contact:
    name: Lanesurf support
    url: https://docs.lanesurf.com
    email: support@lanesurf.com
  license:
    name: Proprietary. Use is subject to the Lanesurf Terms of Service
    url: https://www.lanesurf.com/terms
servers:
  - url: https://agent.lanesurf.com
    description: Production
security:
  - bearerAuth: []
tags:
  - name: Broker loads
    description: A broker's agent posts a load and gets it covered.
  - name: Authentication
    description: >-
      Sign up as a carrier or a brokerage with a work email and a one-time code,
      and see who a key belongs to.
  - name: Broker setup
    description: >-
      What Lanesurf's agents tell carriers about a brokerage, and whether
      carrier outreach is on.
  - name: Carrier trucks
    description: A carrier's agent says where its trucks are and when they're free.
  - name: Carrier lanes
    description: A carrier's agent saves the lanes the carrier runs (its terminals).
  - name: Carrier loads
    description: A carrier's agent finds loads, bids on one, and follows its bids.
  - name: System
    description: Service health.
paths:
  /v1/carrier/loads/{load_id}/bids:
    parameters:
      - $ref: '#/components/parameters/CarrierLoadID'
    post:
      tags:
        - Carrier loads
      summary: Bid on a load
      description: >
        Tells the broker who owns the load that this carrier wants it,
        optionally at a rate. The bid shows up

        on the broker's Lanesurf dashboard as an inbound bid, with the carrier's
        MC/DOT and dispatch contact. The

        broker's team follows up with the dispatcher by email or phone. A bid is
        not a booking: Lanesurf does

        not book the load. Confirm with the dispatcher first. Bids that look
        like a mistake (e.g. an absurd rate)

        may be held for review.


        Only verified carriers can bid (403 `verification_required`). The body
        is optional: no body, an empty

        body or `{}` means "I want to run this, send me your rate". `rate` is
        all-in USD; leave it out to ask

        for the broker's rate. `truck_id` must be one of this key's active
        trucks. One bid per carrier per

        load across all of that carrier's keys (the carrier is its DOT number,
        or its MC number if it has no

        DOT): sending again updates that bid (200, `action: updated` or
        `unchanged`), until the broker has

        accepted it (409 `bid_decided`). A declined bid can be sent again; a new
        rate reopens it. Follow the

        outcome with `GET /v1/carrier/bids`.
      operationId: bidOnLoad
      requestBody:
        required: false
        description: >-
          Optional. No body, an empty body or `{}` bids with no rate, truck or
          note, which asks for the broker's rate.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BidInput'
            example:
              rate: 1900
              truck_id: c1d2e3f4-0000-4000-8000-000000000001
              note: Empty in Dallas Fri 8am
      responses:
        '200':
          description: >
            This carrier already had a bid on this load: it was updated with the
            new terms (`action: updated`),

            or nothing changed (`action: unchanged`). Same `bid_id`; the broker
            sees the new rate on it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Bid'
              example:
                bid_id: b7e1c2d3-0000-4000-8000-0000000000b1
                load_id: 8f14e45f-0000-4000-8000-0000000000a1
                rate: 1850
                status: submitted
                created_at: '2026-10-20T09:00:00Z'
                action: updated
        '201':
          description: 'Bid placed (`action: created`). Its status is `submitted`.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Bid'
              example:
                bid_id: b7e1c2d3-0000-4000-8000-0000000000b1
                load_id: 8f14e45f-0000-4000-8000-0000000000a1
                rate: 1900
                truck_id: c1d2e3f4-0000-4000-8000-000000000001
                note: Empty in Dallas Fri 8am
                status: submitted
                created_at: '2026-10-20T09:00:00Z'
                action: created
        '400':
          description: >
            `invalid_request`: `rate` isn't a positive amount up to 1,000,000,
            `note` is over 1,000 bytes,

            or `truck_id` isn't one of this key's active trucks.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/VerifiedCarrierOnly'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: >
            - `bid_decided`: the broker already accepted this carrier's bid, so
            it can't change.

            - `already_bid`: another key of the same carrier is placing a bid on
            this load right now. Try again
              in a few seconds; your request then updates that bid.
            - `bid_update_limit`: this bid was already changed the most times
            allowed (5). It stands as it is.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                decided:
                  summary: The broker already accepted
                  value:
                    error: >-
                      the broker already accepted your bid on this load; it
                      can't be changed
                    code: bid_decided
                in_progress:
                  summary: Another key's bid is still being placed
                  value:
                    error: >-
                      you already bid on this load (by another key of your
                      carrier, still being placed; try again shortly)
                    code: already_bid
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/Internal'
        '502':
          $ref: '#/components/responses/Upstream'
        '503':
          $ref: '#/components/responses/CarrierUnavailable'
components:
  parameters:
    CarrierLoadID:
      name: load_id
      in: path
      required: true
      description: The `load_id` from a search or matches result.
      schema:
        type: string
        format: uuid
  schemas:
    BidInput:
      type: object
      properties:
        rate:
          type: number
          minimum: 1
          maximum: 500000
          description: >-
            All-in USD, rounded to the cent. Optional; leave it out to ask for
            the broker's rate.
        truck_id:
          type: string
          format: uuid
          description: Which of this key's active trucks would run it.
        note:
          type: string
          maxLength: 1000
          description: >-
            Up to 1,000 characters of plain text. The broker sees it as your
            note.
    Bid:
      type: object
      required:
        - bid_id
        - load_id
        - status
        - created_at
      properties:
        bid_id:
          type: string
          format: uuid
        load_id:
          type: string
          format: uuid
        rate:
          type: number
        truck_id:
          type: string
          format: uuid
        note:
          type: string
        status:
          type: string
          enum:
            - submitted
            - accepted
            - declined
            - load_closed
            - incomplete
          description: >
            `submitted`: the broker has it and the load is open. `accepted` /
            `declined`: the broker's choice on

            this bid. `load_closed`: the load was covered some other way,
            closed, or

            booked to someone else, and the broker made no choice on this bid.
            `incomplete`: the bid was recorded

            but never reached the broker (a failure mid-bid); POST it again to
            finish it (within 2 minutes from

            the same key with its original terms, after that from any of the
            carrier's keys with the new terms).
        created_at:
          type: string
          format: date-time
        action:
          type: string
          enum:
            - created
            - updated
            - unchanged
          description: >
            Only in the reply to `POST /v1/carrier/loads/{load_id}/bids`.
            `created`: a new bid. `updated`: this

            carrier's existing bid now has the new terms. `unchanged`: same
            terms as before.
    Error:
      type: object
      required:
        - error
        - code
      properties:
        error:
          type: string
          description: A message for people.
          example: invalid API key
        code:
          type: string
          description: A stable machine-readable code. Branch on this, not on `error`.
          enum:
            - missing_api_key
            - invalid_api_key
            - wrong_role
            - verification_required
            - invalid_request
            - missing_fields
            - not_found
            - already_covered
            - invalid_state
            - already_bid
            - bid_decided
            - idempotency_in_progress
            - idempotency_key_reused
            - idempotency_key_required
            - load_rejected
            - offer_changed
            - bid_update_limit
            - existing_customer
            - already_redeemed
            - rate_limited
            - invalid_code
            - signup_expired
            - broker_name_taken
            - broker_name_mismatch
            - unavailable
            - upstream_error
            - internal
          example: invalid_api_key
        missing:
          type: array
          description: '`missing_fields` only: exact field names or paths still needed.'
          items:
            type: string
        next_step:
          allOf:
            - $ref: '#/components/schemas/NextStep'
          description: >-
            On signup errors and on every broker load tool's errors
            (`list_loads`, `post_load`, `get_load`, `load_outreach`, accept,
            decline, covered).
        current_rate:
          type: number
          description: '`offer_changed` only: the offer''s rate now.'
        request_id:
          type: string
          description: >-
            This request's id (also the `X-Request-Id` response header). Quote
            it to Lanesurf support.
          example: req_0192f3a4-7b1c-7d2e-9f00-1a2b3c4d5e6f
    NextStep:
      type: string
      description: >-
        For the agent. Exactly what to do next and which MCP tool to call (REST
        path in brackets).
  responses:
    Unauthorized:
      description: >-
        `missing_api_key` (no `Authorization` header) or `invalid_api_key`
        (wrong, malformed or revoked key).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: invalid API key
            code: invalid_api_key
    VerifiedCarrierOnly:
      description: >
        `verification_required`: only verified carriers can do this. A carrier
        account under review

        (`needs_review`) can post and manage trucks and lanes and list its own
        bids, but can't search loads,

        read a load, get truck matches, list outreach or bid. A broker key gets
        `wrong_role`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: >-
              your carrier account is under review; until Lanesurf verifies it
              you can manage trucks and lanes and list your bids, but you can't
              search loads, view loads, get matches or bid
            code: verification_required
    NotFound:
      description: '`not_found`: no such load, offer, truck, lane or signup for this key.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    TooManyRequests:
      description: >
        `rate_limited`: too many requests. Signup has limits per contact, per
        carrier and per IP (the 300 per 10 minutes

        limit groups IPv6 addresses by /64). Every authenticated `/v1` route is
        limited to 120 requests per minute

        per API key, counted on each Lanesurf server. Wait `Retry-After`

        seconds, then retry.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: too many requests for this API key; slow down
            code: rate_limited
    Internal:
      description: '`internal`: unexpected error. Safe to retry later.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Upstream:
      description: >-
        `upstream_error`: a Lanesurf system behind the API failed. Safe to retry
        later.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: a Lanesurf system behind the API failed; try again later
            code: upstream_error
    CarrierUnavailable:
      description: >-
        `unavailable`: Lanesurf couldn't check the API key right now (the key
        may be fine; don't ask for a new one): wait `Retry-After` (30) seconds
        and send the same request again. Or carrier routes can't run right now;
        retry later.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  headers:
    RetryAfter:
      description: Seconds to wait before trying again.
      schema:
        type: integer
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: ls_live_<key>
      description: One key per broker rep or per carrier signup. Keep it secret.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.