{
  "openapi": "3.0.1",
  "info": {
    "title": "Product Photo to 3D Model with Real-World Scale",
    "description": "Turns product photos into web-ready GLB models scaled to the real dimensions you give, oriented front-forward, with the pivot on the floor. Ready to drop into Shopify, WooCommerce, Wix or any model-viewer page.",
    "version": "0.1",
    "x-build-id": "9K5kqpGShJoxlCI8G"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/toolsheder~photo-to-3d/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-toolsheder-photo-to-3d",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/toolsheder~photo-to-3d/runs": {
      "post": {
        "operationId": "runs-sync-toolsheder-photo-to-3d",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/toolsheder~photo-to-3d/run-sync": {
      "post": {
        "operationId": "run-sync-toolsheder-photo-to-3d",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "items",
          "providerApiKey"
        ],
        "properties": {
          "items": {
            "title": "Products",
            "type": "array",
            "description": "One entry per product. Give 2 or 3 photos from different angles, and the real dimensions in millimetres. The dimensions are what make the model the right size in AR, so they are not optional.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "title": "Product id",
                  "description": "Used as the file name. Letters, digits, dot, dash and underscore."
                },
                "imageUrls": {
                  "type": "array",
                  "title": "Photo URLs",
                  "description": "Public image URLs. The first one is treated as the front view.",
                  "items": {
                    "type": "string"
                  }
                },
                "widthMm": {
                  "type": "integer",
                  "title": "Width in mm",
                  "description": "Real width of the product in millimetres, side to side."
                },
                "heightMm": {
                  "type": "integer",
                  "title": "Height in mm",
                  "description": "Real height of the product in millimetres, floor to top."
                },
                "depthMm": {
                  "type": "integer",
                  "title": "Depth in mm",
                  "description": "Real depth of the product in millimetres, front to back."
                },
                "yawDegrees": {
                  "type": "integer",
                  "title": "Rotation in degrees",
                  "description": "Leave empty to let the actor decide. Set 90, 180 or 270 if the model faces the wrong way."
                },
                "targetPolycount": {
                  "type": "integer",
                  "title": "Provider mesh density",
                  "description": "How many faces to ask the provider for. Leave empty and Meshy does no remeshing of its own, while Tripo uses 30000. Smart topology models build to this number directly and accept at most 15000."
                },
                "fabrics": {
                  "type": "array",
                  "title": "Fabrics",
                  "description": "For upholstered furniture: the fabrics it is sold in, each as { \"name\", \"swatchUrl\" }. Each one becomes a variant the shopper can switch in the viewer and in AR. The swatch photograph (the kind a shop already shows, draped and lit) is turned into a seamless tile with relief and repeated over the model at real size, so the weave shows at any zoom. The fabric as photographed stays as the first variant. Costs no provider credits and adds about a megabyte per fabric.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string",
                        "title": "Name",
                        "description": "Name shown to the shopper on this fabric's variant button, e.g. \"Anthology Beige\"."
                      },
                      "swatchUrl": {
                        "type": "string",
                        "title": "Swatch Url",
                        "description": "URL of the shop's swatch photograph of this fabric. Its sharpest square becomes the tile."
                      },
                      "finish": {
                        "type": "string",
                        "enum": [
                          "weave",
                          "leather",
                          "velvet"
                        ],
                        "description": "What the material is, since the photo cannot say: a weave is matte with a soft sheen and its relief; leather is smoother, glossier, without sheen and with a firmer grain; velvet is the mattest, with a strong sheen and almost no relief. Default weave.",
                        "title": "Finish"
                      }
                    },
                    "required": [
                      "name",
                      "swatchUrl"
                    ]
                  }
                },
                "build": {
                  "type": "object",
                  "title": "Build from dimensions",
                  "description": "Build the product from its dimensions instead of generating it from photos: { \"kind\": ..., \"params\": { ... } }. Generators do worst on shapes that a few numbers describe fully (they invent lumps and stains), so these are built exactly, for no provider credits. All params in mm. boxy-sofa: widthMm, heightMm, depthMm (body), seatHeightMm, armWidthMm, armHeightMm, backHeightMm, backDepthMm, chaiseDepthMm, chaiseWidthMm (the chaise module, its arm included), chaiseSide (left/right), seatSectionMm (seat split into sections this wide; larger than the seat for one piece), quiltMm (tufting cell size, 0 for plain), backCushionMm (width of loose back cushions; else upholstered back blocks), sideCushion (true/false), armInsetMm (the free arm stops this far short of the seat front), chaiseOpenMm (the chaise's open end in front of its arm), pillows, pillowMm; imageUrls are only for reference, fabrics dress it. upholstered-bed: mattressWidthMm, mattressLengthMm, headboardHeightMm (from the floor), baseHeightMm (the upholstered box the mattress lies in, default 350), frameMm (round the mattress at the sides and the foot, default 50), headboardDepthMm (default 120), channels (vertical rolls across the headboard, default one about every 150 mm), bedding (true/false: a duvet, a throw and pillows, default true); imageUrls are only for reference, fabrics dress it. drum-shade: diameterMm, heightMm, colour (#rrggbb, else read from the photo), cordMm, canopyDiameterMm, canopyHeightMm, cordColour, linerColour (inner layer of a two-layer wall), diffuserColour + diffuserHoleMm (a plain glowing bottom with a round opening), spokes + ringOuterMm + ringInnerMm (the fitting inside), socket (true: E27 holder and bulb), ringDropMm (ring below the top rim), rimBeadMm + rimColour (rolled, bound rims); with a Claude key, every construction param you leave out is read by Claude from the photos, from build.referenceImageUrls (the maker's photos into the shade, from below, with a tape) and from build.notes (what the maker wrote about how it is made), and the output row lists what nothing showed in buildGuessed; imageUrls [front photo, bottom photo (optional, makes the bottom a glowing disc), ornament (optional: the maker's perforation artwork for the whole wall, unrolled, holes dark)]. The wall is the front photo unwrapped, with the sides and back mirrored from it unless the ornament is given. flat (record sleeve, book, picture): widthMm, heightMm, depthMm; imageUrls [front image, back image (optional, else the front's border colour)]; with a Claude key the face is found in each image and only it is used, so a margin, table or shadow round it is not printed on the model. slatted-armchair: widthMm, depthMm, heightMm, seatHeightMm, armHeightMm, sideSlats, backSlats, backDepthMm, woodLengthMm (real length the wood crop covers), fabricWidthMm (real width the fabric crop covers), badge (true/false); imageUrls [wood crop, fabric crop] cut from the product photos; with a Claude key the counts and heights you leave out are read from build.referenceImageUrls, and with build.cutCrops true imageUrls are the product photos themselves and Claude cuts the wood and fabric from them.",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "boxy-sofa",
                        "upholstered-bed",
                        "drum-shade",
                        "flat",
                        "slatted-armchair"
                      ],
                      "title": "Kind",
                      "description": "Which builder makes the product: boxy-sofa, upholstered-bed, drum-shade, flat or slatted-armchair."
                    },
                    "params": {
                      "type": "object",
                      "title": "Params",
                      "description": "The builder's dimensions and options, in millimetres. The Build field above lists them for each kind."
                    },
                    "notes": {
                      "type": "string",
                      "title": "Notes",
                      "description": "For a drum shade: what the maker wrote about how it is made, as they wrote it. A figure here wins over a photo."
                    },
                    "referenceImageUrls": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "title": "Reference Image Urls",
                      "description": "Photos Claude reads and never builds from: the maker's construction shots, or product photos when imageUrls are crops."
                    },
                    "cutCrops": {
                      "type": "boolean",
                      "title": "Cut Crops",
                      "description": "For a slatted armchair: imageUrls are product photos, and Claude cuts the wood and fabric from them. Needs a Claude key."
                    },
                    "artworkUrl": {
                      "title": "Maker's artwork",
                      "type": "string",
                      "editor": "textfield",
                      "description": "For a drum shade: the maker's own production artwork for the wall (the unrolled strip with the perforation), as a PDF cutting file, an SVG or a PNG. The pattern is then the production one all the way round, and the sheet's real size is checked against the diameter."
                    },
                    "reading": {
                      "title": "Kept reading",
                      "type": "object",
                      "editor": "json",
                      "description": "For a drum shade or a slatted armchair: the buildReading of an earlier run of this product. Built from as it is, with no Claude call, so a rerun uses no Claude credits and comes out the same."
                    }
                  },
                  "required": [
                    "kind",
                    "params"
                  ]
                },
                "clothFromGallery": {
                  "type": "boolean",
                  "title": "Dress it in the cloth from its own gallery",
                  "description": "For a generated sofa, armchair or bed sold in one cloth, with no swatch to give: Claude looks through imageUrls for a close-up of the cloth and for lit faces of the whole product, and the model wears that cloth at its real size, in the colour the photos show, as its only material, with no 'as generated' variant. Ignored when fabrics are given. Needs a Claude key unless clothReading is given."
                },
                "clothReading": {
                  "type": "object",
                  "title": "Cloth reading from an earlier run",
                  "description": "With clothFromGallery: the output row's clothReading from an earlier run. The model is dressed from it as it is, with no Claude call, so a rerun uses no Claude credits and comes out the same.",
                  "editor": "json"
                },
                "photographedFabricName": {
                  "type": "string",
                  "title": "Name of the fabric as photographed",
                  "description": "Label of the first variant, the fabric in the product photograph. Default \"As photographed\"."
                },
                "weaveMm": {
                  "type": "integer",
                  "title": "Weave tile size, mm",
                  "description": "How much of the product the smallest tile cut from the swatch covers. A swatch photograph shows roughly 30 cm of fabric and a draped one allows a tile from a third of it, so 90 is right for most; raise it if the weave looks too fine on the model, lower it if too coarse. A swatch photographed flat gives a tile of up to 80% of the photo, scaled to match, so a coarse pattern repeats less often.",
                  "default": 90,
                  "minimum": 20,
                  "maximum": 500
                },
                "aiModel": {
                  "type": "string",
                  "title": "Model for this product",
                  "description": "Overrides the run-wide generation model for this one product. Meshy only.",
                  "enum": [
                    "latest",
                    "meshy-5",
                    "meshy-6",
                    "meshy-7",
                    "meshy-t1",
                    "meshy-t2"
                  ]
                }
              },
              "required": [
                "id",
                "imageUrls",
                "widthMm",
                "heightMm",
                "depthMm"
              ],
              "additionalProperties": false
            }
          },
          "provider": {
            "title": "Generation provider",
            "enum": [
              "meshy",
              "tripo"
            ],
            "type": "string",
            "description": "Which image-to-3D service to call. Meshy has models that build clean, hard-surface topology, which suits machined goods. Tripo can align the mesh to your front photo, which helps when models come out facing the wrong way. Both are asked for GLB only: a provider's USDZ comes back at the generator's own scale and skips every correction this actor makes, and model-viewer converts the corrected GLB for iOS by itself.",
            "default": "meshy"
          },
          "aiModel": {
            "title": "Meshy generation model",
            "enum": [
              "latest",
              "meshy-7",
              "meshy-6",
              "meshy-5",
              "meshy-t2",
              "meshy-t1"
            ],
            "type": "string",
            "description": "Which Meshy model builds the mesh. The default reconstructs a surface from the photograph, which reads soft goods well but leaves a machined product slightly wavy, as if modelled in clay. The smart topology models build clean geometry at a chosen face count instead and separate the object into its real parts, which suits hard-surface goods. They work with a single photo only. Ignored by Tripo.",
            "default": "latest"
          },
          "providerApiKey": {
            "title": "Provider API key",
            "type": "string",
            "description": "Your own Meshy or Tripo key. You bring your own, so the models are licensed to you directly by the provider with nobody in between. A paid provider tier is normally required if you intend to sell or redistribute the models."
          },
          "anthropicApiKey": {
            "title": "Anthropic API key: Claude checks and corrects every model",
            "type": "string",
            "description": "Optional. For a generated model, Claude looks at it from four sides beside the photos: turns it to face the way the photos do when it faces away (normalised again, no credits, confirmed by a second look), and lists in the output row what a shopper would notice as wrong, a quality rating and a builder that would make the product exactly. A yawDegrees you set always wins. For a flat build, Claude finds the face in the images. For a slatted-armchair build, it reads the counts and heights and, with build.cutCrops, cuts the wood and fabric. For a drum-shade build, Claude reads how the shade is made (inner layer, diffuser and its opening, spokes, ring, holder, rolled rims) from the photos, the maker's construction photos and notes, and checks it once against the built model; params you give win. For a boxy-sofa build, Claude looks at the photos and the dimensions and fills in every param you did not give (arm width, which end the chaise is on, back cushions, tufting, scatter cushions) before the sofa is built, and corrects them once if the model then differs grossly from the photo. Params you give always win. At most two Claude calls per sofa, billed to this key; the output row lists which params came from Claude, your input or the builder's defaults. Without a key (here or as ANTHROPIC_API_KEY in the environment) the sofa is built from your params alone."
          },
          "openrouterApiKey": {
            "title": "OpenRouter API key, instead of an Anthropic one",
            "type": "string",
            "description": "Optional. Does the same as the Anthropic key, with the calls going to Claude through OpenRouter and billed there. Used only when no Anthropic key is given; falls back to OPENROUTER_API_KEY in the environment."
          },
          "scaleMode": {
            "title": "How to apply your dimensions",
            "enum": [
              "exact",
              "uniform"
            ],
            "type": "string",
            "description": "Exact stretches the mesh to match your width, height and depth precisely, which is what you want when your dimensions are right. Uniform keeps the generated proportions and fits the model inside your dimensions instead.",
            "default": "exact"
          },
          "maxTriangles": {
            "title": "Triangle budget",
            "minimum": 5000,
            "maximum": 200000,
            "type": "integer",
            "description": "Meshes above this are simplified once, on our side. 60000 is the measured sweet spot: within 0.35% of an unsimplified mesh in rendered pixels, well under AR limits. The provider's own remeshing stays off because it was measured to introduce holes.",
            "default": 60000
          },
          "smoothingPasses": {
            "title": "Surface smoothing",
            "minimum": 0,
            "maximum": 12,
            "type": "integer",
            "description": "Generators reconstruct a surface from the photograph rather than model one, so a machined product arrives with its flat faces creased and its round edges wavy, as if pressed out of clay. Each pass takes some of that out. The default of eight is higher than it would be without planar snapping, which puts the flatness and the edges back afterwards, so smoothing can work on the noise without having to preserve structure. Lower it for upholstery and rugs, where the unevenness is part of the product.",
            "default": 8
          },
          "spikeThreshold": {
            "title": "Spike repair",
            "minimum": 0,
            "maximum": 10,
            "type": "number",
            "description": "How far a vertex may stand off the surface its own neighbours describe, measured in median edge lengths, before it is treated as noise and pulled back. Generators leave about two per cent of vertices standing proud, and on a dark product they show as bright crystalline chips scattered over what should be one flat colour. Smoothing cannot reach them. The default of 2.5 moved 2.04 per cent of vertices on a measured flood light and left 0.01 per cent. Set 0 to leave the mesh exactly as generated.",
            "default": 2.5
          },
          "normalPasses": {
            "title": "Flatten what should be flat",
            "minimum": 0,
            "maximum": 6,
            "type": "integer",
            "description": "Off by default. It filters the field of face normals, weighting each neighbour by how nearly it faces the same way, so a surface that should be one plane settles onto one plane and genuine creases stay sharp. That straightens a bowed bracket arm. The downside is that gentle curvature is not a crease either, so it gets divided into planes with creases between them, and on a matte surface those look like crushed foil. Measured against plain smoothing on two products, five smoothing passes and no normal filtering came out cleaner than four passes of filtering on both. Use it when a mesh is too wavy for smoothing alone.",
            "default": 0
          },
          "planarSnap": {
            "title": "Straighten flat panels and their edges",
            "type": "boolean",
            "description": "Smoothing averages, and averaging makes a wobbly edge wobble less but cannot make it straight. This finds the regions of the mesh that are already almost flat, fits one plane to each, and then puts every vertex where those planes say it belongs: on the plane, on the line where two planes cross, or at the point where three meet. Flat panels and their edges then look manufactured instead of soft-edged. Curved surfaces have no flat regions to find, so they are left untouched, and any vertex the planes would move more than two per cent of the model's size is left where it is.",
            "default": true
          },
          "revolveSnap": {
            "title": "Make round products round",
            "type": "boolean",
            "description": "Straightening flat panels leaves curved surfaces alone, so drum shades, vases, round tables and stools stay as the generator made them: a wall that should be one smooth cylinder comes out rippled and the rim wobbles. This cuts the model into horizontal bands and checks each one all the way round. Vertices move only when the footprint is a circle and most bands have one radius in every direction; each wall vertex then goes to its band's measured radius and keeps its height. Inner and outer walls are fitted separately, so a thin shade keeps its thickness. Sofas, chairs and anything else that is not round are left untouched.",
            "default": true
          },
          "evenFlatColour": {
            "title": "Even out plain colour",
            "type": "boolean",
            "description": "Generators paint the photographer's reflections and the source JPEG's blocking into the colour map as though they were the paint. Without its textures, a flood light's housing is a clean flat plane; with the colour map back on, it is covered in faint scuffs. This evens them out, but only where the product has no detail to lose. The decision is made on how much the colour varies locally, so a printed rating, the edge of a bezel, a wood grain or a fabric weave keeps every pixel it had, and a plain panel becomes plain.",
            "default": true
          },
          "minRoughness": {
            "title": "Lowest roughness on non-metal",
            "minimum": 0,
            "maximum": 1,
            "type": "number",
            "description": "Generators paint patches of near-mirror gloss onto surfaces that are plainly matte in the photograph, and those patches read as bright smears sliding over the product as it turns. This raises roughness to a floor everywhere the material is not metal; screws, clips and chrome keep their shine. Do not set it too high: a floor of 0.45 removed the smears from a black flood light but left the housing looking washed out, because a fully matte dark surface scatters ambient light evenly and comes out grey. The photograph's black was deeper than that, and so was the model's own colour texture, so the grey came from the roughness floor. 0.32 kept the black and kept the smears away. Leave at 0 for lacquer, glaze and polished stone, where the gloss is part of the product; try 0.3 to 0.4 for powder-coated metal, moulded plastic and matte paint.",
            "default": 0
          },
          "occlusionResolution": {
            "title": "Baked ambient occlusion",
            "enum": [
              "512",
              "1024",
              "256",
              "0"
            ],
            "type": "string",
            "description": "glTF has a slot for ambient occlusion and no image-to-3D generator fills it, so a viewer lights the gap between two heat sink fins as brightly as the flat panel next to it, and the model looks flat however good the mesh is. This bakes one from the model's own shape, with no provider credits and nothing needed from you. Occlusion is a low-frequency signal, so 512 px is usually indistinguishable from 1024 and takes a quarter of the time. Turn it off if you are relighting the model yourself in an engine that computes occlusion at render time.",
            "default": "512"
          },
          "remeshTopology": {
            "title": "Face shape when remeshing",
            "enum": [
              "triangle",
              "quad"
            ],
            "type": "string",
            "description": "Only used for products that set a target polycount. For hard-surface goods it has more effect than any other setting in this actor. Without remeshing, the generator returns its raw reconstruction: on an LED flood light that meant a hundred lenses as blobs of random size, which no post-processing can turn into an array. Remeshed with quads, the same photos and the same settings produced round, evenly sized lenses in rows. It has a cost and does not suit every product: on a round garden light the same setting improved the lens array just as much but left the housing rim ragged and the cooling fins gone. Use quads when the product is panels, frames and repeating detail; leave it off when the shape is rounded, and compare the two before running a catalogue through either.",
            "default": "triangle"
          },
          "maxTextureSize": {
            "title": "Maximum texture size",
            "enum": [
              "512",
              "1024",
              "2048"
            ],
            "type": "string",
            "description": "Textures larger than this are resized. 2048 is the ceiling Shopify gives for mobile web.",
            "default": "2048"
          },
          "textureFormat": {
            "title": "Texture format",
            "enum": [
              "jpeg",
              "png",
              "webp"
            ],
            "type": "string",
            "description": "JPEG is the safe default because it works everywhere, including Android AR. WebP makes smaller files but relies on a glTF extension that Google's Scene Viewer does not list as supported, so AR on Android may fail.",
            "default": "jpeg"
          },
          "textureResolution": {
            "title": "Texture detail to generate",
            "enum": [
              "2k",
              "4k"
            ],
            "type": "string",
            "description": "What to ask the provider for before the model is resized to your ceiling. 4k costs the same on most plans and downscales to a visibly sharper 2048 texture, which shows on fabric and wood.",
            "default": "2k"
          },
          "dracoCompression": {
            "title": "Draco compression",
            "type": "boolean",
            "description": "Shrinks geometry considerably, but Google's Scene Viewer does not list Draco among the glTF extensions it supports, so AR on Android may fail. Leave off unless you only need the web viewer.",
            "default": false
          },
          "pivotOnFloor": {
            "title": "Put the origin on the floor",
            "type": "boolean",
            "description": "Generators put the origin at the centre of the object, which makes it sink into the floor in AR. Shopify requires the origin at the product's base.",
            "default": true
          },
          "recenterHorizontally": {
            "title": "Centre horizontally",
            "type": "boolean",
            "description": "Centres the model on X and Z so it turns around itself rather than orbiting.",
            "default": true
          },
          "storeName": {
            "title": "Storage name",
            "pattern": "^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$",
            "maxLength": 63,
            "type": "string",
            "description": "Models are saved to a named storage so the download links keep working. Reuse the same name across runs to keep one library. Unnamed storage is deleted after seven days.",
            "default": "photo-to-3d-models"
          },
          "reuseGeneratedMeshes": {
            "title": "Keep generated meshes for reruns",
            "type": "boolean",
            "description": "Stores each generated mesh so a later run with the same photos and provider settings reuses it instead of paying for generation again. Dimensions, rotation, triangle budget and texture settings are all applied afterwards, so correcting any of them costs no provider credits. Each model delivered is still charged as usual. The stored meshes are large, tens of megabytes each, and count towards your Apify storage, so turn this on while you are getting a catalogue right and off once you are done.",
            "default": false
          },
          "concurrency": {
            "title": "Products at once",
            "minimum": 1,
            "maximum": 8,
            "type": "integer",
            "description": "How many products to process in parallel. Leave empty to match your provider's queue limit. Raise the actor's memory if you raise this."
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}