> ## 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.

# Verify the code

> Send the 8-digit code (brokers also say who they are). Get your API key.

Step 2 of 2. Send the 8-digit code the person received. Returns the API key **once**; store it
securely. Codes expire after 10 minutes and allow 5 attempts. If the answer was lost on the way, send
the same code again while it's valid: you get a working key, or `409 already_redeemed` once the first
key has been used.

**Brokers** also send `name`, `job_title` and `company_name` (and optionally `phone` and `website`).
If any required one is missing you get `422 missing_fields` **before** an attempt is used, so ask for
them and send the same code again. The MC/DOT number and email come from step 1. The brokerage is
created unverified with carrier outreach **off** (`activated: false`): Lanesurf reviews it, then turns
outreach on. Until then loads you post are saved and show `stalled`.

**Carriers**: Lanesurf checks the carrier by DOT/MC number and compares the email's domain with the
carrier's record. `principal.verification` is:

* `verified`: the check confirmed the carrier (the email's domain matches an email on the carrier's
  record, and the record doesn't show the carrier's authority as inactive). Full access: trucks, lanes, load search, load details, truck
  matches and bids.
* `needs_review`: the check couldn't confirm it: no match, carrier not found, check unavailable, inactive or
  broker-only authority, an MC and a DOT of different carriers, or a shared mailbox domain (free
  mail, ISP mail such as att.net or comcast.net, disposable inboxes), which never counts as a
  match because anyone can hold a mailbox there. Your carrier account is under review until Lanesurf's
  team verifies it; the same key then gets full access. Until then the key 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 (`403 verification_required`).

Nobody is refused for not matching. Every reply has `next_step`.


## OpenAPI

````yaml /openapi.yaml post /v1/signup/{signup_id}/verify
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/signup/{signup_id}/verify:
    post:
      tags:
        - Authentication
      summary: Finish signup with the code
      description: >
        Step 2 of 2. Send the 8-digit code. Returns the API key once; store it
        securely. Codes expire after

        10 minutes and allow 5 attempts; re-sending a valid code after a lost
        answer returns a working key, or

        409 already_redeemed once that key has been used. Brokers also send
        name, job_title and company_name

        (phone, website optional); missing ones answer 422 missing_fields before
        an attempt is used. A new

        brokerage starts with carrier outreach off until Lanesurf reviews it
        (activated false). Carriers get

        principal.verification verified (the email's domain matches an email on
        the carrier's

        record) or needs_review (until Lanesurf's team verifies the account)
        (under review: trucks, lanes and bids list only). Every reply has
        next_step.
      operationId: verifySignup
      parameters:
        - name: signup_id
          in: path
          required: true
          description: The `signup_id` from `POST /v1/signup`.
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VerifySignupRequest'
            examples:
              carrier:
                summary: A carrier
                value:
                  code: '48291307'
              broker:
                summary: A brokerage
                value:
                  code: '48291307'
                  name: Dana Reyes
                  job_title: Carrier Sales Manager
                  company_name: Acme Freight LLC
                  phone: '+12145550100'
                  website: https://acmefreight.example.com
      responses:
        '201':
          description: The new API key. Follow `next_step`.
          headers:
            Cache-Control:
              $ref: '#/components/headers/NoStore'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IssuedKey'
              examples:
                carrier_needs_review:
                  summary: A carrier under review
                  value:
                    api_key: ls_live_...
                    principal:
                      key_id: 0b1c2d3e-4f50-4617-8293-a4b5c6d7e8f9
                      key_prefix: ls_live_1a2b
                      role: carrier
                      verification: needs_review
                      carrier:
                        legal_name: EXAMPLE TRUCKING LLC
                        mc_number: '123456'
                        dot_number: '1234567'
                        contact_email: dispatch@exampletrucking.example.com
                    message: >-
                      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
                    next_step: >-
                      Give the person api_key now to store securely (for example
                      as this connector's Authorization: Bearer header): it is
                      shown only once; never repeat it afterwards. Tell the
                      person: your carrier account is under review; ...
                      Meanwhile post trucks with post_truck, save lanes with
                      save_lane and follow bids with list_bids.
                broker:
                  summary: A new brokerage
                  value:
                    api_key: ls_live_...
                    principal:
                      key_id: 1c2d3e4f-5061-4728-93a4-b5c6d7e8f9a0
                      key_prefix: ls_live_9z8y
                      role: broker
                      broker_id: 6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d
                      rep_name: Dana Reyes
                    activated: false
                    message: >-
                      Lanesurf reviews new brokerages before carrier outreach
                      starts; loads you post are saved and start sourcing once
                      outreach is on
                    next_step: >-
                      Give the person api_key now to store securely ...
                      Meanwhile review the brokerage setup with get_broker_setup
                      and fill in working hours, payment terms and CC emails
                      with update_broker_setup.
        '400':
          description: >-
            `invalid_request`: e.g. the code isn't 8 digits, a website that
            isn't http(s), a job title over 100 characters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignupError'
        '404':
          description: '`not_found`: no such signup.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignupError'
        '409':
          description: >-
            `existing_customer`: the brokerage already works with Lanesurf;
            don't sign up, their Lanesurf admin or account manager gives them
            access. `already_redeemed`: this signup was already completed and
            its key is in use. `broker_name_taken`: a brokerage with this
            `company_name` is already set up with Lanesurf.
            `broker_name_mismatch`: this signup already created the brokerage
            under another name.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignupError'
        '410':
          description: >-
            `signup_expired`: the code expired (10 minutes) or ran out of
            attempts (5). Start again.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignupError'
        '422':
          description: >
            `missing_fields` (brokers: `name`, `job_title` or `company_name` is
            missing; no attempt was used) or

            `invalid_code` (wrong code; the message says how many attempts are
            left).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignupError'
              examples:
                missing_fields:
                  value:
                    error: >-
                      to set up the brokerage, send job_title, company_name with
                      the code; no attempt was used
                    code: missing_fields
                    missing:
                      - job_title
                      - company_name
                    next_step: >-
                      Ask the person for job_title, company_name, then call
                      verify_signup again with the same signup_id and code plus
                      name, job_title and company_name (phone and website
                      optional). No attempt was used.
                invalid_code:
                  value:
                    error: wrong code; 4 attempt(s) left
                    code: invalid_code
                    next_step: >-
                      Ask the person to check the code in the email and call
                      verify_signup again with the same signup_id.
        '429':
          $ref: '#/components/responses/SignupRateLimited'
        '500':
          $ref: '#/components/responses/SignupInternal'
        '503':
          $ref: '#/components/responses/SignupUnavailable'
      security: []
components:
  schemas:
    VerifySignupRequest:
      type: object
      required:
        - code
      description: >
        Carriers send `code`. Brokers also send `name`, `job_title` and
        `company_name` (required) and

        optionally `phone` and `website`. MC/DOT and the email come from `POST
        /v1/signup`.
      properties:
        code:
          type: string
          pattern: ^[0-9]{8}$
          example: '48291307'
        role:
          type: string
          enum:
            - carrier
            - broker
          description: Optional. If sent it must match the signup.
        name:
          type: string
          maxLength: 200
          description: 'Brokers: the person''s full name.'
          example: Dana Reyes
        job_title:
          type: string
          maxLength: 100
          description: 'Brokers: the person''s job title at the brokerage.'
          example: Carrier Sales Manager
        company_name:
          type: string
          maxLength: 200
          description: 'Brokers: the brokerage''s name, as carriers should hear it.'
          example: Acme Freight LLC
        phone:
          type: string
          description: 'Brokers, optional: E.164; a 10-digit US number is accepted.'
          example: '+12145550100'
        website:
          type: string
          maxLength: 300
          description: >-
            Brokers, optional: an http(s) address; `https://` is added when no
            scheme is given.
          example: https://acmefreight.example.com
    IssuedKey:
      type: object
      required:
        - api_key
        - principal
        - next_step
      properties:
        api_key:
          type: string
          example: ls_live_...
          description: Shown once. Store it securely.
        principal:
          $ref: '#/components/schemas/Principal'
        activated:
          type: boolean
          description: >
            Brokers only. `false` until Lanesurf reviews the new brokerage and
            turns carrier outreach on. Loads

            posted before then are saved and show `stalled`.
        message:
          type: string
          description: >
            For people. A carrier under review: "your carrier account is under
            review; ...". A new brokerage:

            outreach starts after Lanesurf's review.
        next_step:
          $ref: '#/components/schemas/NextStep'
    SignupError:
      type: object
      required:
        - error
        - code
        - next_step
      properties:
        error:
          type: string
          description: A message for people.
        code:
          type: string
          enum:
            - invalid_request
            - missing_fields
            - not_found
            - invalid_code
            - signup_expired
            - broker_name_taken
            - broker_name_mismatch
            - existing_customer
            - already_redeemed
            - rate_limited
            - unavailable
            - internal
        missing:
          type: array
          description: '`missing_fields` only: the fields to ask for.'
          items:
            type: string
            example: job_title
        next_step:
          $ref: '#/components/schemas/NextStep'
        retry_after_seconds:
          type: integer
          description: MCP only; REST sends the `Retry-After` header.
    Principal:
      type: object
      required:
        - key_id
        - key_prefix
        - role
      properties:
        key_id:
          type: string
          format: uuid
        key_prefix:
          type: string
          example: ls_live_1a2b
        role:
          type: string
          enum:
            - broker
            - carrier
        verification:
          type: string
          enum:
            - verified
            - needs_review
          description: >
            Carriers only. `verified`: confirmed automatically (the signup
            email's domain matches an email on the

            carrier's record; shared mailbox domains such as ISP mail never
            count; the authority isn't shown as

            inactive) or by Lanesurf's team.

            `needs_review`: the carrier account is under review (trucks, lanes
            and the bid list only).
        carrier:
          $ref: '#/components/schemas/CarrierProfile'
        broker_id:
          type: string
          format: uuid
          description: Brokers only. The brokerage.
        rep_name:
          type: string
          description: Brokers only.
    NextStep:
      type: string
      description: >-
        For the agent. Exactly what to do next and which MCP tool to call (REST
        path in brackets).
    CarrierProfile:
      type: object
      description: >-
        Carriers only. The carrier record from the identity check, and the
        contact proved with the code. Empty fields are left out.
      properties:
        legal_name:
          type: string
        mc_number:
          type: string
        dot_number:
          type: string
        contact_email:
          type: string
        contact_phone:
          type: string
  headers:
    NoStore:
      description: Responses that carry secrets are never cached.
      schema:
        type: string
        example: no-store
    RetryAfter:
      description: Seconds to wait before trying again.
      schema:
        type: integer
  responses:
    SignupRateLimited:
      description: >-
        `rate_limited`: too many signups for this email, this MC/DOT number or
        this network. Wait `Retry-After` seconds.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SignupError'
    SignupInternal:
      description: '`internal`: unexpected error. Safe to retry later.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SignupError'
    SignupUnavailable:
      description: >
        `unavailable`: signup can't run right now (code sending or a Lanesurf
        system is down). Retry later;

        when `Retry-After` is set, wait that many seconds. If the carrier check
        can't run, signup still works:

        the carrier is `needs_review`.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SignupError'
  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.