{
 "openapi": "3.1.0",
 "info": {
  "title": "Cutlab agent API",
  "version": "1.0.0",
  "summary": "Capabilities, preliminary estimate and request for quotation for CNC cutting at Cutlab (Estonia)",
  "description": "Public API for AI agents acting for customers. A preliminary estimate is a range, not an offer. A request for quotation (RFQ) is not an order: Cutlab replies by e-mail to the customer address with a written quote, usually within one working day. Files are accepted only as public https links. The API sends no e-mail itself.",
  "contact": {
   "name": "Cutlab",
   "email": "hello@cutlab.ee",
   "url": "https://cutlab.ee/for-ai-agents"
  }
 },
 "servers": [
  {
   "url": "https://agent.cutlab.ee"
  }
 ],
 "paths": {
  "/v1/capabilities": {
   "get": {
    "operationId": "getCapabilities",
    "summary": "What Cutlab can make: machine, materials, rates, delivery, limits",
    "responses": {
     "200": {
      "description": "Facts about the workshop",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/v1/estimate": {
   "post": {
    "operationId": "estimateQuote",
    "summary": "Preliminary price range for simple rectangular parts",
    "description": "Only rectangular parts. Uses public rates (sheet cutting from 30 EUR per sheet, typical shaped work 60-80 EUR, minimum order 100 EUR; logistics threshold 150 EUR outside Estonia). The result is a range, not an offer.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/EstimateRequest"
       },
       "example": {
        "parts": [
         {
          "width_mm": 300,
          "length_mm": 600,
          "quantity": 10
         }
        ],
        "thickness_mm": 18,
        "material": "birch plywood",
        "destination_country": "DE",
        "lang": "en"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Preliminary range",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/EstimateResponse"
        }
       }
      }
     },
     "422": {
      "$ref": "#/components/responses/Invalid"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  },
  "/v1/rfq": {
   "post": {
    "operationId": "submitRfq",
    "summary": "Submit a request for quotation (not an order)",
    "description": "Creates a request at Cutlab. contact_email is required: Cutlab confirms the request there. Files only as public https links in file_links. Send an Idempotency-Key header to make retries safe.",
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string",
       "maxLength": 80
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/RfqRequest"
       },
       "example": {
        "contact_email": "buyer@example.com",
        "contact_name": "Anna Schmidt",
        "company": "Schmidt Design GmbH",
        "customer_type": "B2B",
        "country": "DE",
        "language": "en",
        "description": "20 sets of birch plywood 18 mm parts for shelving, DXF drawings linked below. Need a written quote and lead time. Delivery to Hamburg.",
        "material": "birch plywood 18 mm",
        "quantity": "20 sets",
        "deadline": "2026-11-30",
        "parts": [
         {
          "width_mm": 400,
          "length_mm": 800,
          "quantity": 40
         }
        ],
        "file_links": [
         "https://example.com/files/shelf.dxf"
        ],
        "agent": {
         "name": "ExampleAssistant",
         "vendor": "Example Inc",
         "acting_for": "Schmidt Design GmbH"
        },
        "customer_consent_to_contact": true
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Duplicate of an earlier request (same Idempotency-Key or same e-mail and description)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RfqResponse"
        }
       }
      }
     },
     "201": {
      "description": "Request received",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/RfqResponse"
        }
       }
      }
     },
     "422": {
      "$ref": "#/components/responses/Invalid"
     },
     "429": {
      "$ref": "#/components/responses/RateLimited"
     }
    }
   }
  }
 },
 "components": {
  "responses": {
   "RateLimited": {
    "description": "Too many requests, see Retry-After",
    "headers": {
     "Retry-After": {
      "schema": {
       "type": "integer"
      }
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "Invalid": {
    "description": "Invalid request",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "code": {
        "type": "string"
       },
       "message": {
        "type": "string"
       },
       "retry_after": {
        "type": "integer"
       }
      }
     }
    }
   },
   "EstimateRequest": {
    "type": "object",
    "required": [
     "parts"
    ],
    "properties": {
     "parts": {
      "type": "array",
      "minItems": 1,
      "maxItems": 50,
      "items": {
       "type": "object",
       "required": [
        "width_mm",
        "length_mm"
       ],
       "properties": {
        "shape": {
         "type": "string",
         "enum": [
          "rectangle"
         ],
         "default": "rectangle"
        },
        "width_mm": {
         "type": "number",
         "minimum": 5,
         "maximum": 4000
        },
        "length_mm": {
         "type": "number",
         "minimum": 5,
         "maximum": 4000
        },
        "quantity": {
         "type": "integer",
         "minimum": 1,
         "maximum": 500,
         "default": 1
        }
       }
      }
     },
     "sheet": {
      "type": "object",
      "description": "Optional sheet size, default 1250 x 2500 mm, at most 2070 x 4000 mm",
      "properties": {
       "width_mm": {
        "type": "number"
       },
       "length_mm": {
        "type": "number"
       }
      }
     },
     "thickness_mm": {
      "type": "number"
     },
     "material": {
      "type": "string",
      "maxLength": 120
     },
     "destination_country": {
      "type": "string",
      "pattern": "^[A-Z]{2}$"
     },
     "lang": {
      "type": "string",
      "enum": [
       "en",
       "et",
       "ru"
      ],
      "default": "en"
     }
    }
   },
   "EstimateResponse": {
    "type": "object",
    "properties": {
     "estimate": {
      "type": "object",
      "properties": {
       "currency": {
        "type": "string"
       },
       "price_excl_vat": {
        "type": "object",
        "properties": {
         "low": {
          "type": "number"
         },
         "high": {
          "type": "number"
         }
        }
       },
       "covers": {
        "type": "string"
       },
       "sheets_needed": {
        "type": "object"
       },
       "minimum_order_eur": {
        "type": "number"
       },
       "minimum_order_applied": {
        "type": "boolean"
       },
       "logistics_threshold_eur": {
        "type": "number"
       },
       "below_logistics_threshold": {
        "type": "boolean"
       }
      }
     },
     "assumptions": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "vat": {
      "type": "string"
     },
     "not_an_offer": {
      "type": "boolean",
      "const": true
     },
     "disclaimer": {
      "type": "object",
      "properties": {
       "lang": {
        "type": "string"
       },
       "text": {
        "type": "string"
       }
      }
     },
     "next_step": {
      "type": "object"
     }
    }
   },
   "RfqRequest": {
    "type": "object",
    "required": [
     "contact_email",
     "description",
     "customer_consent_to_contact"
    ],
    "properties": {
     "contact_email": {
      "type": "string",
      "format": "email",
      "description": "Customer e-mail for confirmation (required)"
     },
     "contact_name": {
      "type": "string",
      "maxLength": 100
     },
     "company": {
      "type": "string",
      "maxLength": 100
     },
     "customer_type": {
      "type": "string",
      "enum": [
       "B2B",
       "private"
      ]
     },
     "country": {
      "type": "string",
      "pattern": "^[A-Z]{2}$"
     },
     "language": {
      "type": "string",
      "enum": [
       "ru",
       "et",
       "en",
       "fi",
       "de",
       "other"
      ]
     },
     "description": {
      "type": "string",
      "minLength": 20,
      "maxLength": 4000
     },
     "material": {
      "type": "string",
      "maxLength": 120
     },
     "quantity": {
      "type": "string",
      "maxLength": 60
     },
     "deadline": {
      "type": "string",
      "maxLength": 60
     },
     "parts": {
      "type": "array",
      "maxItems": 30,
      "items": {
       "type": "object"
      }
     },
     "file_links": {
      "type": "array",
      "maxItems": 10,
      "items": {
       "type": "string",
       "format": "uri",
       "pattern": "^https://"
      },
      "description": "Public https links to drawings or models. Attachments are not supported."
     },
     "agent": {
      "type": "object",
      "properties": {
       "name": {
        "type": "string"
       },
       "vendor": {
        "type": "string"
       },
       "acting_for": {
        "type": "string"
       }
      }
     },
     "customer_consent_to_contact": {
      "type": "boolean",
      "const": true,
      "description": "The customer agrees to be contacted by e-mail about this request"
     }
    }
   },
   "RfqResponse": {
    "type": "object",
    "properties": {
     "status": {
      "type": "string",
      "enum": [
       "received"
      ]
     },
     "reference": {
      "type": "string"
     },
     "message": {
      "type": "string"
     },
     "will_contact_email": {
      "type": "string"
     },
     "response_time": {
      "type": "string"
     },
     "note": {
      "type": "string"
     },
     "duplicate": {
      "type": "boolean"
     }
    }
   }
  }
 },
 "x-rate-limits": {
  "GET /v1/capabilities": "60 per minute per IP",
  "POST /v1/estimate": "30 per minute per IP",
  "POST /v1/rfq": "10 requests per minute per IP, 5 created requests per hour per IP, 60 created requests per day in total"
 },
 "x-email-channel": {
  "address": "rfq@agents.cutlab.ee",
  "attachments": "not stored; send links to files in the text",
  "note": "Plain-text e-mail with the same information as POST /v1/rfq; the reply goes to the customer address in the message."
 }
}