LoadOptimizer.ai Saved loads API

Keep the runs that matter under a name, within your plan's limit per problem type.

Operations 4

POST /saved-loads Save a run as a saved load #
GET /saved-loads List saved loads #
GET /saved-loads/{id} Get a saved load #
DELETE /saved-loads/{id} Release a saved load #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/loadoptimizer-ai:loadoptimizer-ai-saved-loads-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

loadoptimizer-ai-saved-loads-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Load Optimizer Saved loads API
  version: 2.0.0
  summary: Asynchronous box-packing / load-optimization API.
  description: 'Submitting work is **asynchronous**: every solve is a *job* you create, poll, then collect.


    This is the documentation of the **Load Optimizer API v2**: it describes what `/v2` supports;

    what it does not describe is not supported.


    ## Job lifecycle

    `queued → running → succeeded | failed | cancelled` (last three terminal). Poll `GET /jobs/{id}` until terminal.


    ## Conventions

    Values from a fixed set (enum values, in a request body or in list filters such as `status`, `saved` and

    `sort`) are matched without regard to case, and come back in the spelling published here: `"MM"` reads

    back as `"mm"`. Names and codes keep their case: group names, a SKU''s code (`externalId`, also as a

    filter) and system-catalogue slugs are case-sensitive. The idempotency fingerprint compares the body as you

    sent it: an enum value in another case makes a different body, so while the key is kept (see `Idempotency-Key`)

    the same key gets the `409`.'
  contact:
    email: contact@loadoptimizer.ai
servers:
- url: https://api.loadoptimizer.ai/v2
  description: Production environment of the Load Optimizer API.
  x-internal: false
security:
- ApiKey: []
tags:
- name: Saved loads
  description: Keep the runs that matter under a name, within your plan's limit per problem type.
paths:
  /saved-loads:
    post:
      tags:
      - Saved loads
      operationId: saveLoad
      summary: Save a run as a saved load
      description: 'Keeps one of your succeeded orders as a saved load, under the name you give it. A saved load is the run itself, kept: it has the run''s id, and the run''s request (`/jobs/{id}/input`), result, instructions and share link stay where they are, under `/jobs/{id}/...`. The name is the run''s name, so saving sets it and `PUT /jobs/{id}/name` changes it for both. Your plan allows a number of saved loads per problem type. At that limit the save is refused with `422`. A valid `replace` names one of your saved loads of the same problem type, which is released in the same call whether or not you are at the limit; a refused save releases nothing. Saving a run that is already saved answers `409` and changes nothing, so a retry after a timeout tells you the first attempt landed.'
      parameters:
      - name: jobId
        in: query
        required: true
        description: 'The id of the run to save: one of your orders that has succeeded. A value that is not a UUID in its 36-character form is rejected with `400` against `jobId`.'
        schema:
          type: string
          format: uuid
          maxLength: 36
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 256
                  description: The name to keep it under. Trimmed, and stored on the run.
                replace:
                  type:
                  - string
                  - 'null'
                  format: uuid
                  maxLength: 36
                  description: The id of one of your saved loads of the same problem type, released in the same call whether or not you are at the limit; a refused save releases nothing. A value that is not a UUID in its 36-character form, or that names a saved load of another problem type, is rejected with `400` against `/replace`.
            examples:
              save:
                summary: Save a run
                value:
                  name: Rotterdam week 40
              replace:
                summary: Save it in place of an older one
                value:
                  name: Rotterdam week 41
                  replace: 01975cbe-8d17-7a64-b2c9-4f06a1d3e5b8
      responses:
        '201':
          description: Saved. The run is now a saved load.
          headers:
            Location:
              description: URL of the saved load.
              schema:
                type: string
                format: uri
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SavedLoad'
              examples:
                saved:
                  summary: The run, kept as a saved load
                  value:
                    id: 01975cbc-1f40-7d21-9b3e-5a7c2e8f0d19
                    name: Rotterdam week 40
                    problemType: LoadPlanning
                    createdAt: '2026-09-28T08:12:33.412+00:00'
                    savedAt: '2026-10-01T14:03:10.007+00:00'
        '400':
          $ref: '#/components/responses/ValidationProblem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: 'The run is not one of your orders (`code: "job_not_found"`: unknown, another account''s, or a loading-instructions job), or `replace` names no saved load of yours (`code: "saved_load_not_found"`).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
              examples:
                unknownJob:
                  $ref: '#/components/examples/JobNotFound'
                unknownSavedLoad:
                  $ref: '#/components/examples/SavedLoadNotFound'
        '409':
          description: 'The run has not succeeded (`code: "job_not_succeeded"`), or it is already saved (`code: "saved_load_exists"`; nothing was changed).'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
              examples:
                alreadySaved:
                  summary: The run is already a saved load
                  value:
                    type: https://tools.ietf.org/html/rfc9110#section-15.5.10
                    title: This run is already saved.
                    status: 409
                    code: saved_load_exists
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedMediaType'
        '422':
          description: 'Your plan''s saved-load limit for this problem type is reached (`code: "max_saved_loads"`); `detail` names the limit. Release a saved load, or name it in `replace`.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
              examples:
                limitReached:
                  summary: Every place for this problem type is taken
                  value:
                    type: https://tools.ietf.org/html/rfc4918#section-11.2
                    title: Saved-load limit reached.
                    status: 422
                    code: max_saved_loads
                    detail: The account keeps at most 10 saved loads of this problem type.
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerProblem'
    get:
      tags:
      - Saved loads
      operationId: listSavedLoads
      summary: List saved loads
      description: Your saved loads, a page at a time, the most recently saved first unless you sort otherwise. Each item is the same `SavedLoad` that `GET /saved-loads/{id}` returns. Follow `nextCursor` until it is null, passing the same filters, `sort` and `direction` on every page. There is no total count. Every invalid parameter is reported at once, in one `400` with one `errors[]` entry per parameter, whose `pointer` is the parameter's name.
      parameters:
      - name: problemType
        in: query
        required: false
        style: form
        explode: true
        description: Only saved loads of one of these problem types. Repeat the parameter for several.
        schema:
          type: array
          items:
            type: string
            enum:
            - LoadPlanning
            - MixedPalletizing
      - name: q
        in: query
        required: false
        description: 'Only saved loads whose `name` contains this text, ignoring case. Matched literally: `%` and `_` are ordinary characters. Leading and trailing whitespace is ignored. At most 256 characters.'
        schema:
          type: string
          maxLength: 256
      - name: savedFrom
        in: query
        required: false
        description: Only loads saved at or after this moment (inclusive). An RFC 3339 date-time with an offset; in a URL, send a `+` offset as `%2B`.
        schema:
          type: string
          format: date-time
          maxLength: 33
      - name: savedTo
        in: query
        required: false
        description: Only loads saved before this moment (exclusive). Same format as `savedFrom`, and not earlier than it.
        schema:
          type: string
          format: date-time
          maxLength: 33
      - name: sort
        in: query
        required: false
        description: 'The order of the list: when it was saved, when the run was submitted, its name, or its problem type. Within equal names or problem types the most recently saved comes first. Within equal times (`savedAt`, `createdAt`) the order follows the id of the run, in the direction you ask for. Under `sort=name`, a load whose name was cleared comes last in both directions.'
        schema:
          type: string
          enum:
          - savedAt
          - createdAt
          - name
          - problemType
          default: savedAt
      - name: direction
        in: query
        required: false
        description: 'The sort direction: `desc` by default for `savedAt` and `createdAt` (newest first), `asc` for `name` and `problemType`.'
        schema:
          type: string
          enum:
          - asc
          - desc
      - name: limit
        in: query
        required: false
        description: Saved loads per page, 1 to 50. Default 50.
        schema:
          type: integer
          format: int32
          minimum: 1
          maximum: 50
          default: 50
      - name: cursor
        in: query
        required: false
        description: The `nextCursor` of the previous page, passed back unchanged with the same `sort` and `direction`. A value this API did not issue, one issued by the other list, or one issued for another sort or direction, is rejected with `400`. At most 4,096 characters.
        schema:
          type: string
          maxLength: 4096
      responses:
        '200':
          description: One page of saved loads.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SavedLoadPage'
              examples:
                onePage:
                  summary: Everything fits on one page
                  value:
                    items:
                    - id: 01975cbc-1f40-7d21-9b3e-5a7c2e8f0d19
                      name: Rotterdam week 40
                      problemType: LoadPlanning
                      createdAt: '2026-09-28T08:12:33.412+00:00'
                      savedAt: '2026-10-01T14:03:10.007+00:00'
                    - id: 01975cbe-8d17-7a64-b2c9-4f06a1d3e5b8
                      name: Rotterdam week 39
                      problemType: LoadPlanning
                      createdAt: '2026-09-21T08:12:33.412+00:00'
                      savedAt: '2026-09-24T09:30:00.000+00:00'
                    nextCursor: null
        '400':
          $ref: '#/components/responses/ValidationProblem'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerProblem'
  /saved-loads/{id}:
    parameters:
    - $ref: '#/components/parameters/SavedLoadId'
    get:
      tags:
      - Saved loads
      operationId: getSavedLoad
      summary: Get a saved load
      description: One of your saved loads, by its id, which is also its run's job id. An unknown id, a released load and another account's load all answer `404`.
      responses:
        '200':
          description: The saved load. Its request (`/jobs/{id}/input`), result, instructions and share link are under `/jobs/{id}/...`, with the same id.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SavedLoad'
              examples:
                saved:
                  summary: A saved load
                  value:
                    id: 01975cbc-1f40-7d21-9b3e-5a7c2e8f0d19
                    name: Rotterdam week 40
                    problemType: LoadPlanning
                    createdAt: '2026-09-28T08:12:33.412+00:00'
                    savedAt: '2026-10-01T14:03:10.007+00:00'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/SavedLoadNotFoundProblem'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerProblem'
    delete:
      tags:
      - Saved loads
      operationId: deleteSavedLoad
      summary: Release a saved load
      description: 'Stops keeping the run, so it no longer counts against your limit. The run itself is untouched: its result and name stay, and `GET /jobs?saved=false` lists it again. To undo, save it again. Never limited by your plan, so an account over its limit can always make room.'
      responses:
        '204':
          description: Released. The run itself is untouched.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/SavedLoadNotFoundProblem'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerProblem'
components:
  responses:
    SavedLoadNotFoundProblem:
      description: 'Unknown saved-load id, one that is not a UUID in its 36-character form, one already released, or one belonging to another account: all answer identically (no existence leak).'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            unknownSavedLoad:
              $ref: '#/components/examples/SavedLoadNotFound'
    PayloadTooLarge:
      description: 'The request body is larger than the API will read (`code: "payload_too_large"`). Permanent for that body: split the order into smaller jobs rather than retrying it unchanged.'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            bodyTooLarge:
              summary: A body past the size the API reads
              value:
                type: https://tools.ietf.org/html/rfc9110#section-15.5.14
                title: Payload too large.
                status: 413
                code: payload_too_large
                detail: The request body is larger than this API accepts. Split the order into smaller jobs.
    ValidationProblem:
      description: 'Validation failed: `code: "validation_failed"`, with `errors[]` naming each offending field, query parameter or header. Every 400 on `/v2` has this shape; see Errors & troubleshooting.'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            invalidGeometry:
              summary: A cargo line with a geometry type the API does not implement
              value:
                type: https://tools.ietf.org/html/rfc9110#section-15.5.1
                title: Validation failed.
                status: 400
                code: validation_failed
                errors:
                - pointer: /cargo/0/geometry/type
                  code: validation_failed
                  message: Only 'box' geometry is supported.
    ServerProblem:
      description: 'The request could not be completed for a reason the API did not anticipate. Transient as far as a caller can tell: retry, and if it persists contact support. The cause is recorded internally and is deliberately absent from the body, so there is nothing here to branch on beyond `code`.'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            internalServerError:
              summary: An unanticipated failure while handling the request
              value:
                type: https://tools.ietf.org/html/rfc9110#section-15.6.1
                title: Internal server error.
                status: 500
                code: internal_server_error
                detail: The request could not be completed. Retry; if it keeps failing, contact support.
    UnsupportedMediaType:
      description: 'The request body was sent under a content type other than `application/json`, or without one (`code: "unsupported_media_type"`). These operations read JSON only.'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            wrongContentType:
              summary: A body sent as something other than JSON
              value:
                type: https://tools.ietf.org/html/rfc9110#section-15.5.16
                title: Unsupported media type.
                status: 415
                code: unsupported_media_type
                detail: Send the request body as application/json.
    Unauthorized:
      description: Missing, invalid or revoked API key. Empty body.
    Forbidden:
      description: 'The API key is valid, but the account''s plan does not include customer-API access (`code: "customer_api_not_entitled"`). Permanent, not transient: retrying will not help; the account''s plan must add customer-API access first.'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            notEntitled:
              $ref: '#/components/examples/NotEntitled'
    RateLimited:
      description: 'Too many requests, too fast (`code: "rate_limit_exceeded"`). The account may make **300 requests per minute** across `/v2`, replenished continuously, and every operation except `GET /health` counts. The request was not carried out: wait the number of seconds in the **`Retry-After`** header, then send it again. A full queue and a used-up monthly quota answer `429` on `POST /jobs` only.'
      headers:
        Retry-After:
          description: Seconds to wait before retrying.
          schema:
            type: integer
            format: int32
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
          examples:
            rateLimited:
              summary: Too many requests too fast
              value:
                title: Too many requests.
                status: 429
                code: rate_limit_exceeded
                detail: The account exceeded the request rate for the customer API. Retry after the number of seconds in the Retry-After header.
  schemas:
    ProblemCode:
      type: string
      description: Stable, machine-readable top-level error-code registry, by HTTP status.
      enum:
      - validation_failed
      - ambiguous_source
      - override_field_not_allowed
      - customer_api_not_entitled
      - mixed_palletizing_not_entitled
      - load_planning_not_entitled
      - link_sharing_not_entitled
      - request_body_not_supported
      - libraries_not_entitled
      - library_read_only
      - internal_server_error
      - job_not_found
      - result_not_ready
      - artifact_not_ready
      - saved_load_not_found
      - library_not_found
      - library_entry_not_found
      - job_already_terminal
      - job_not_succeeded
      - saved_load_exists
      - external_id_taken
      - payload_too_large
      - unsupported_media_type
      - max_items_per_job
      - max_carriers_per_job
      - max_carrier_instances_per_job
      - max_saved_loads
      - max_library_entries
      - too_many_active_jobs
      - monthly_quota_exceeded
      - rate_limit_exceeded
    SavedLoadPage:
      type: object
      required:
      - items
      - nextCursor
      description: One page of `GET /saved-loads`.
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/SavedLoad'
        nextCursor:
          type:
          - string
          - 'null'
          pattern: ^[A-Za-z0-9_-]+$
          description: 'Pass it as `cursor` for the next page; null on the last page. Opaque: do not build or parse it.'
    Problem:
      type: object
      description: 'RFC 9457 `problem+json`. `code` is stable & machine-readable when present; `errors[].pointer` locates

        the offending field, query parameter or header. Two `/v2` errors have an **empty body** instead:

        `401` and the idempotency `409`.

        See [Errors & troubleshooting](errors.html).'
      properties:
        type:
          type: string
          format: uri
          description: 'A reference for the response''s status code, not for the specific failure: two failures with different `code` values share one `type`. RFC 9457 permits `about:blank` here; this API never sends that, and the `429` responses carry no `type` at all. Switch on `code`, never on this field.'
        title:
          type: string
        status:
          type: integer
          format: int32
        detail:
          type: string
          description: Human-readable explanation, present on some errors and often naming the limit value that was exceeded. Never switch on it; switch on code.
        code:
          $ref: '#/components/schemas/ProblemCode'
        errors:
          type: array
          description: Field-level problems. Only on a 400 `validation_failed`.
          items:
            type: object
            properties:
              pointer:
                type: string
                description: For a body field, a JSON Pointer (RFC 6901) into the request body, over the member names as this contract spells them (camelCase, also when you sent another case), e.g. /carriers/0/externalId. A name you chose yourself (a group name, an overrides member) appears as sent, with ~ written as ~0 and / as ~1. For a query parameter or a header, its name without a leading /, e.g. limit or Idempotency-Key. An empty string means the body as a whole.
              code:
                type: string
                enum:
                - validation_failed
                - ambiguous_source
                - library_entry_not_found
                - override_field_not_allowed
                description: 'validation_failed, unless a field code applies: ambiguous_source or library_entry_not_found on the libraryId of a job carrier or cargo line, or override_field_not_allowed on its overrides.'
              message:
                type: string
      required:
      - title
      - status
    SavedLoad:
      type: object
      required:
      - id
      - name
      - problemType
      - createdAt
      - savedAt
      description: A run you kept. Its id is the run's job id; the request (`/jobs/{id}/input`), result, instructions and share link stay under `/jobs/{id}/...`.
      properties:
        id:
          type: string
          format: uuid
          description: 'The run''s job id: its request, result, instructions and share link are under `/jobs/{id}/...`.'
        name:
          type:
          - string
          - 'null'
          maxLength: 256
          description: The run's name. Set when saving; null only when it was cleared afterwards with `PUT /jobs/{id}/name`.
        problemType:
          type: string
          enum:
          - LoadPlanning
          - MixedPalletizing
        createdAt:
          type: string
          format: date-time
          description: When the run was submitted (UTC).
        savedAt:
          type: string
          format: date-time
          description: When it was saved (UTC).
  examples:
    NotEntitled:
      summary: The key is valid; the plan is not
      value:
        type: https://tools.ietf.org/html/rfc9110#section-15.5.4
        title: The account's plan does not include the customer API.
        status: 403
        code: customer_api_not_entitled
        detail: 'Upgrade the account to a plan that includes customer-API access: https://app.loadoptimizer.ai/home/billing'
    SavedLoadNotFound:
      summary: Unknown, released, or someone else's saved load
      value:
        type: https://tools.ietf.org/html/rfc9110#section-15.5.5
        title: Saved load not found.
        status: 404
        code: saved_load_not_found
    JobNotFound:
      summary: Unknown id, or someone else's job
      value:
        type: https://tools.ietf.org/html/rfc9110#section-15.5.5
        title: Job not found.
        status: 404
        code: job_not_found
  parameters:
    SavedLoadId:
      name: id
      in: path
      required: true
      description: The saved load's id, which is also its run's job id.
      schema:
        type: string
        format: uuid
        maxLength: 36
  securitySchemes:
    ApiKey:
      type: apiKey
      in: header
      name: X-Api-Key
      description: 'Customer API key bound to your account, e.g. `X-Api-Key: ck_live_...`. Create it in the web app (see https://app.loadoptimizer.ai/docs/api-keys); the full key is shown only once.'
x-provenance:
  method: harvested
  publisher: LoadOptimizer.ai
  source: https://www.loadoptimizer.ai/docs/loadoptimizer-openapi.yaml
  note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
    stamped by stamp-openapi-provenance.py (roadmap#793)