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

> ## Agent Instructions
> The PartFinder API is served at https://api.partfinder.dev. Authenticate with `Authorization: Bearer $PARTFINDER_API_KEY`; create an account at https://console.partfinder.dev/sign-up and pick pay as you go or a monthly or yearly plan (see https://partfinder.dev/pricing), then create a key. Pay as you go starts with 100 free credits, once per person and per company.
> Install the PartFinder agent skill with `npx skills add https://docs.partfinder.dev` (skill file: https://docs.partfinder.dev/skill.md).
> The OpenAPI document at https://api.partfinder.dev/v1/openapi.json is the source of truth for request and response schemas.
> What each call costs and current plans: https://api.partfinder.dev/llms.txt.

# Analyze a BOM

> Submit a bill of materials for supply-chain risk analysis. Use it whenever your user asks to scan or analyze a BOM or a list of parts, even a list of one line. Every line is identified, its origin and current distributor availability resolved, and a risk score computed from manufacturing geography, live disruption exposure, lead-time volatility and sourcing gaps across the BOM.

The work runs in the background: this call answers `202` at once with the BOM id, and `GET /v1/bom/{id}` carries the report, partial while `status` is `processing` and full once it is `complete`. Time to complete varies with the parts in the BOM. One call carries up to 500 lines; a BOM is kept until you delete it.



## OpenAPI

````yaml https://api.partfinder.dev/v1/openapi.json post /v1/bom
openapi: 3.1.0
info:
  title: PartFinder API
  version: 1.0.0
  license:
    name: Proprietary
    url: https://partfinder.dev/terms
  description: >-
    Supply-chain intelligence for industrial parts: risk scoring, supply
    availability, datasheets, disruption events, BOM analysis, alternates, part
    search and part comparison. Responses are structured for an AI agent to read
    — every score carries its scale, direction and an interpretation, every
    measure carries its unit, every successful response carries `as_of`, and
    every error carries an `error` code, usually with a `summary` you can relay,
    except a 413 (request body too large), which has no body.
servers:
  - url: https://api.partfinder.dev
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: Confirm an API key works.
  - name: Parts
    description: 'Research one part: risk, supply, datasheet, events, alternates.'
  - name: BOMs
    description: Analyze a bill of materials line by line.
  - name: Events
    description: >-
      Supply-chain disruptions: events, the countries they hit, and port and
      sea-route activity.
  - name: Search
    description: >-
      Find parts for a part number or a description, with specifications and
      stock.
  - name: Compare
    description: >-
      Put parts side by side on their specifications, with a verdict per
      specification.
  - name: RFQs
    description: Send requests for quote to suppliers and read their replies.
  - name: Keys
    description: Give each of your own customers a key that sees only its own data.
  - name: Webhooks
    description: >-
      Be told when a supplier replies, or a search or a comparison ends, instead
      of polling.
paths:
  /v1/bom:
    post:
      tags:
        - BOMs
      summary: Analyze a BOM
      description: >-
        Submit a bill of materials for supply-chain risk analysis. Use it
        whenever your user asks to scan or analyze a BOM or a list of parts,
        even a list of one line. Every line is identified, its origin and
        current distributor availability resolved, and a risk score computed
        from manufacturing geography, live disruption exposure, lead-time
        volatility and sourcing gaps across the BOM.


        The work runs in the background: this call answers `202` at once with
        the BOM id, and `GET /v1/bom/{id}` carries the report, partial while
        `status` is `processing` and full once it is `complete`. Time to
        complete varies with the parts in the BOM. One call carries up to 500
        lines; a BOM is kept until you delete it.
      operationId: analyzeBom
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
          example: 6f1c2e9a-3b7d-4c55-9a0e-2d8f41b7c3e1
          description: >-
            Set by your client code, not by a person or a model: generate a new
            value (a UUID) for each submission, and send the same value again
            only when retrying that same request after a timeout. A retry with
            the same key returns the BOM the first request created instead of a
            duplicate. A key is recognised only from the same API key that sent
            it. The body is not compared, so never reuse a key for a different
            or updated BOM. A key is remembered for as long as the BOM it
            created exists; after that BOM is deleted, the same key starts a new
            one. Optional.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BomRequest'
            example:
              name: Controller board rev C
              parts:
                - mpn: TPS54331DR
                  manufacturer: Texas Instruments
                  quantity: 100
                  supplier: Mouser
                - mpn: STM32F407VGT6
                  quantity: 50
                - mpn: 6305-2RS
                  manufacturer: SKF
                  quantity: 10
                  description: Deep groove ball bearing
      responses:
        '202':
          description: Accepted. Analysis has started.
          headers:
            Location:
              description: >-
                The absolute URL of the report, `GET /v1/bom/{id}` on the server
                this request reached.
              schema:
                type: string
            Retry-After:
              description: Seconds to wait before polling the report. Always 5.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Limit:
              description: >-
                Calls allowed in the current window: the minute or the day,
                whichever has fewer calls left.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Remaining:
              description: Calls left in that window.
              schema:
                type: integer
                minimum: 0
            X-RateLimit-Reset:
              description: Seconds until that window resets.
              schema:
                type: integer
                minimum: 1
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BomAccepted'
              example:
                as_of: '2026-09-28T15:49:42.444Z'
                summary: >-
                  Accepted 3 lines. The BOM is being analyzed; poll GET
                  /v1/bom/fc2b3371-7eb7-48cd-8847-70b2d76b0be8 until status is
                  "complete".
                notice: >-
                  Informational only. Risk scores, stock levels, lead times and
                  alternate-part suggestions may be incomplete, delayed or
                  inaccurate. Independently verify before making procurement,
                  engineering, compliance, safety or sourcing decisions.
                bom:
                  id: fc2b3371-7eb7-48cd-8847-70b2d76b0be8
                  name: Controller board rev C
                  status: processing
                  lines: 3
                  created_at: '2026-09-28T15:49:38.809Z'
        '400':
          description: >-
            The body is not valid: no `parts`, a line without `mpn`, or a bad
            quantity.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-RateLimit-Limit:
              description: >-
                Calls allowed in the current window: the minute or the day,
                whichever has fewer calls left.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Remaining:
              description: Calls left in that window.
              schema:
                type: integer
                minimum: 0
            X-RateLimit-Reset:
              description: Seconds until that window resets.
              schema:
                type: integer
                minimum: 1
        '401':
          description: Missing, unknown, revoked or expired key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: >-
            This request was not run and nothing was charged. The error code
            names the case. `credits_exhausted`: your plan's credits for this
            month are used up; upgrade the plan in the PartFinder console.
            `payment_method_required`: your organization is on pay as you go
            with no payment method; add one in the console, or choose a plan.
            `payment_failed`: pay as you go is paused because the last payment
            failed; update the payment method in the console.
            `usage_limit_reached`: your organization, on pay as you go, has
            reached its limit for unpaid usage; calls resume once the current
            payment goes through. With a key made with `POST /v1/keys`, the
            `summary` tells your customer to contact your organization, and the
            answer carries no `billing_url`. The `summary` can be relayed as is;
            retry once the case is resolved.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: credits_exhausted
                summary: >-
                  Your organization's credits for this month are used up, so
                  this request was not run. Upgrade your plan in the PartFinder
                  console at https://console.partfinder.dev/settings/billing,
                  then try again.
                reason: This request needs 75 credits and 0 are left.
                billing_url: https://console.partfinder.dev/settings/billing
          headers:
            X-RateLimit-Limit:
              description: >-
                Calls allowed in the current window: the minute or the day,
                whichever has fewer calls left.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Remaining:
              description: Calls left in that window.
              schema:
                type: integer
                minimum: 0
            X-RateLimit-Reset:
              description: Seconds until that window resets.
              schema:
                type: integer
                minimum: 1
        '403':
          description: >-
            The caller signed in through an AI app without the permission this
            call needs (`partfinder:read` to read, which includes looking up
            parts, alternates and events and uses credits for those;
            `partfinder:write` to change anything); the error is
            `insufficient_scope`. Or the AI app was disconnected in the console;
            the error is `app_disconnected`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-RateLimit-Limit:
              description: >-
                Calls allowed in the current window: the minute or the day,
                whichever has fewer calls left.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Remaining:
              description: Calls left in that window.
              schema:
                type: integer
                minimum: 0
            X-RateLimit-Reset:
              description: Seconds until that window resets.
              schema:
                type: integer
                minimum: 1
        '422':
          description: >-
            More than 500 lines in one call. `reason` states the limit and what
            was sent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-RateLimit-Limit:
              description: >-
                Calls allowed in the current window: the minute or the day,
                whichever has fewer calls left.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Remaining:
              description: Calls left in that window.
              schema:
                type: integer
                minimum: 0
            X-RateLimit-Reset:
              description: Seconds until that window resets.
              schema:
                type: integer
                minimum: 1
        '429':
          description: >-
            Your organization has used its calls for this minute or this day.
            Wait the number of seconds in `Retry-After`, then retry.
          headers:
            Retry-After:
              description: Seconds until the limit resets.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Limit:
              description: >-
                Calls allowed in the current window: the minute or the day,
                whichever has fewer calls left.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Remaining:
              description: Calls left in that window.
              schema:
                type: integer
                minimum: 0
            X-RateLimit-Reset:
              description: Seconds until that window resets.
              schema:
                type: integer
                minimum: 1
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: >-
            The analysis could not be started. Nothing was stored; retry
            shortly.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
          headers:
            X-RateLimit-Limit:
              description: >-
                Calls allowed in the current window: the minute or the day,
                whichever has fewer calls left.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Remaining:
              description: Calls left in that window.
              schema:
                type: integer
                minimum: 0
            X-RateLimit-Reset:
              description: Seconds until that window resets.
              schema:
                type: integer
                minimum: 1
components:
  schemas:
    BomRequest:
      type: object
      properties:
        name:
          description: A label for this BOM, shown back in `GET /v1/bom`.
          type: string
          maxLength: 200
        parts:
          minItems: 1
          type: array
          items:
            type: object
            properties:
              mpn:
                type: string
                minLength: 1
                description: The manufacturer part number. Required.
              manufacturer:
                description: The manufacturer, when the BOM names one.
                anyOf:
                  - type: string
                  - type: 'null'
              quantity:
                description: Units of this line in the build.
                anyOf:
                  - type: integer
                    exclusiveMinimum: 0
                  - type: 'null'
              supplier:
                description: >-
                  Who you buy this line from, when the BOM names one. A line
                  with no supplier is flagged `no_supplier`.
                anyOf:
                  - type: string
                  - type: 'null'
              description:
                description: The line description from the BOM, when there is one.
                anyOf:
                  - type: string
                  - type: 'null'
            required:
              - mpn
          maxItems: 500
          description: >-
            The BOM lines, up to 500 per call; more answers `422 bom_too_large`.
            A file uploaded to `POST /v1/bom/upload` carries up to 2,000 rows in
            one BOM.
      required:
        - parts
    BomAccepted:
      type: object
      properties:
        as_of:
          type: string
          format: date-time
          description: ISO 8601. How current the data in this response is.
        summary:
          type: string
          description: Plain language an agent can relay without re-deriving it.
        notice:
          type: string
          description: Informational-use notice. Always present.
        bom:
          type: object
          properties:
            id:
              type: string
              description: >-
                The BOM id. Use it with `GET /v1/bom/{id}` and `DELETE
                /v1/bom/{id}`.
            name:
              type: string
            status:
              type: string
              enum:
                - processing
                - complete
              description: >-
                `processing` until every line has settled (identified or not);
                then `complete`.
            lines:
              type: integer
              minimum: 0
              description: Lines accepted.
            created_at:
              type: string
              format: date-time
          required:
            - id
            - name
            - status
            - lines
            - created_at
      required:
        - as_of
        - summary
        - notice
        - bom
    Error:
      type: object
      properties:
        error:
          type: string
          enum:
            - authentication_required
            - invalid_key
            - invalid_request
            - not_a_specific_part
            - part_not_found
            - verification_unavailable
            - generation_failed
            - bom_too_large
            - bom_not_found
            - bom_columns_not_found
            - event_not_found
            - rate_limited
            - supplier_opted_out
            - send_failed
            - rfq_not_found
            - rfq_bounced
            - message_refused
            - key_not_allowed
            - insufficient_scope
            - app_disconnected
            - key_not_found
            - key_name_taken
            - webhook_endpoint_not_found
            - not_a_parts_query
            - search_not_found
            - compare_not_found
            - credits_exhausted
            - payment_method_required
            - payment_failed
            - usage_limit_reached
          description: >-
            `authentication_required` when no bearer token was sent.
            `invalid_key` when the key or sign-in is unknown, revoked or expired
            — deliberately indistinguishable — or the sign-in names no
            organization you belong to (the `summary` says what to do).
            `invalid_request` when a required parameter is missing.
            `not_a_specific_part` when the input does not identify one specific
            part. `part_not_found` when no supplier lists that part number
            exactly — usually a typo or a partial number.
            `verification_unavailable` when we could not check whether the part
            is real, and so declined to describe it; temporary, safe to retry.
            `generation_failed` when the report could not be produced, or a
            search or a comparison could not be started. `bom_too_large` when
            one call carries more lines than the limit; `reason` states both
            numbers. `bom_not_found` when no BOM with that id belongs to your
            organization (with a key made with `POST /v1/keys`, to that
            customer). `bom_columns_not_found` when an uploaded file has no
            column we can identify as part numbers; `reason` lists the headers
            seen. `event_not_found` when no active event has that id.
            `rate_limited` when your organization has used its calls for this
            minute or this day; wait the seconds in the `Retry-After` header,
            then retry. `supplier_opted_out` when the supplier asked not to
            receive requests for quote from you, or from anyone through
            PartFinder. `send_failed` when the email could not be sent; nothing
            was stored, safe to retry. `rfq_not_found` when no request for quote
            with that id belongs to your organization (with a key made with
            `POST /v1/keys`, to that customer). `rfq_bounced` when the
            supplier's address could not receive the request; send a new request
            for quote to a working address. `message_refused` when the text was
            not sent; `summary` says what to change before sending again.
            `key_not_allowed` when a key that belongs to one of your customers
            calls an endpoint only your organization's own keys may call, or a
            caller signed in through an AI app manages keys or webhooks.
            `insufficient_scope` when an AI app signed in without the permission
            the call needs (`partfinder:read` to read, which includes looking up
            parts, alternates and events and uses credits for those;
            `partfinder:write` to change anything); the `summary` names it, and
            connecting the app again with it allowed fixes it.
            `app_disconnected` when the AI app the caller signed in through was
            disconnected in the console; signing in again does not help,
            allowing the app again in the console does. `key_not_found` when no
            live end-customer key with that id belongs to your organization.
            `key_name_taken` when a key with that name already exists in your
            organization, revoked keys included. `webhook_endpoint_not_found`
            when no webhook endpoint with that id belongs to your organization
            (with a key made with `POST /v1/keys`, to that customer).
            `not_a_parts_query` when a search query is not about a part; send a
            part number or describe the part. `search_not_found` when no search
            with that id belongs to your organization (with a key made with
            `POST /v1/keys`, to that customer). `compare_not_found` when no
            comparison with that id belongs to your organization (with a key
            made with `POST /v1/keys`, to that customer). `credits_exhausted`
            when your plan's credits for this month are used up; this request
            was not run and nothing was charged. Upgrade the plan at
            `billing_url`, then retry. `payment_method_required` when your
            organization is on pay as you go with no payment method; this
            request was not run and nothing was charged. Add a payment method or
            choose a plan at `billing_url`, then retry. `payment_failed` when
            pay as you go is paused because the last payment failed; this
            request was not run and nothing was charged. Update the payment
            method at `billing_url`, then retry. `usage_limit_reached` when your
            organization, on pay as you go, has reached its limit for unpaid
            usage; this request was not run and nothing was charged. Calls
            resume once the current payment goes through; follow it at
            `billing_url`. With a key made with `POST /v1/keys`, these four
            carry no `billing_url`: the `summary` asks your customer to contact
            your organization.
        summary:
          description: >-
            One sentence you can relay to a user as-is, the same as `summary` on
            a successful response. Present whenever there is something useful to
            say about what went wrong.
          type: string
        reason:
          description: The specific detail behind the error.
          type: string
        billing_url:
          description: >-
            On `credits_exhausted`, `payment_method_required`, `payment_failed`
            and `usage_limit_reached`: the PartFinder console Billing page,
            where your organization manages its plan and payment method. Absent
            for a key made with `POST /v1/keys`, and for an organization whose
            plan is set by its contract.
          type: string
          format: uri
        did_you_mean:
          description: >-
            Real part numbers to retry with. On `not_a_specific_part` they are
            parts of the kind you described; on `part_not_found` they are the
            listed part numbers your input is a prefix of, so `TPS5433` returns
            TPS54331, TPS54332 and so on. Absent when there is nothing to
            suggest. Every entry is a real part number, never a guess.
          type: array
          items:
            type: string
      required:
        - error
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        An API key created in the PartFinder console at
        https://console.partfinder.dev, or a customer key created with `POST
        /v1/keys`. Send as `Authorization: Bearer <key>`. Revocation takes
        effect within approximately one minute.

````

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