LLM与AI智能体集成指南
此页面提供专门为大型语言模型 (LLM)(如 GPT-4、Claude 或 Gemini)设计的上下文说明。您可以直接将此页面提供给您的 AI 助手,以帮助它快速将 Quote3D API 集成到您的项目中。
系统提示
使用以下文本向您的AI助手或代码生成工具(Copilot)解释Quote3D的架构:
You are integrating Quote3D: a REST API for instant 3D-printing quotes, with async quote jobs, webhooks, and an embeddable storefront widget. Follow this contract exactly. Where it contradicts your prior assumptions about quoting APIs, this contract wins.
== 0. TRANSPORT AND ENVELOPE ==
Base URL: https://api.quote3d.com — all paths are versioned under /v2.
Every JSON response uses one envelope: { "success": true, "data": { ... } } on success, and { "success": false, "error": "message" } on failure. File downloads and CSV exports return the raw body instead.
Branch on the HTTP status code, never on the error text — messages get reworded.
== 1. AUTHENTICATION ==
Send the token as 'Authorization: Bearer TOKEN' or 'X-API-Token: TOKEN'. Pick one style and use it consistently.
Tokens are opaque credentials — do not parse them, and do not depend on their internal structure.
Exactly one endpoint needs no authentication: the public upload route in section 2.
Token scopes: a token is either full-access or widget-scoped. A widget-scoped token only reaches what the embedded widget needs; everywhere else it is rejected with 403. Use a full-access server token for webhooks, analytics, usage and quota.
A token may also be restricted to an IP allowlist and may carry an expiry. Both failures surface as 403 and 401 respectively, not as a network error.
== 2. UPLOADING A MODEL ==
Accepted formats: STL, 3MF, OBJ. Uploads above the platform limit (50 MB by default) are rejected.
There are two upload paths. Choose deliberately.
(a) Server-side: POST /v2/file, multipart/form-data, field name 'file', authenticated. Use when the file already sits on your backend.
(b) Browser-direct, two steps: GET /v2/file/upload-id returns data.upload_id, valid for one hour. Then POST /v2/file/public/{upload_id} with multipart field 'file' and NO Authorization header. Prefer this when the shopper's browser holds the file — it keeps large uploads off your server and keeps your token out of client code.
Both paths return a file_id. Keep it; every later call is keyed on it.
File management: GET /v2/file/{file_id} downloads, DELETE /v2/file/{file_id} removes, GET /v2/user/uploads lists (newest first).
Responses carry file_path, which is the authenticated download path (/v2/file/{file_id}) — not a location on disk. Uploads are never reachable as static files, so there is no URL to link to directly.
== 3. OPTIONAL PRE-CHECK ==
POST /v2/printability/{file_id} answers synchronously with dimensions, volume, surface_area and geometric integrity (is_valid, open_edges, non_manifold_edges). Use it to reject unprintable models before spending a quote.
It needs build-volume dimensions: it reads them from the selected printer profile, or you pass x, y and z in the body. If neither is available it returns 400. The body also accepts technology.
== 4. QUOTING IS ASYNCHRONOUS — THIS IS THE PART MOST INTEGRATIONS GET WRONG ==
POST /v2/file/quote/{file_id} does NOT return a price. It answers 202 Accepted with { jobId, status: 'queued', statusUrl, estimatedTime, createdAt }.
POST /v2/file/quote/{file_id}/async is the same endpoint under a second name. Do not build different logic for the two.
Request body, all optional: technology ('FDM' | 'SLA' | 'SLS'; 'RESIN' is an alias for 'SLA'), printer_id, quantity, and the three config objects printer_config, material_config and quote_config.
Anything you omit is resolved for you: request value first, then the user's dashboard profile, then the global profile. So the minimal useful body is often {} or { "quantity": 2 }. Do not invent required fields, and do not send a wall of parameters an integrator would rather configure once in their dashboard.
Then poll GET /v2/jobs/{job_id} and read data.status. Statuses are LOWERCASE: 'queued', 'processing', 'completed', 'failed', 'cancelled'. Terminal statuses are 'completed', 'failed' and 'cancelled'.
A failed calculation still answers HTTP 200, with status 'failed' and data.error = { message, code }. Never treat 200 as success — inspect data.status. This is the single most common bug in generated Quote3D clients.
While processing you may also read data.progress and data.estimatedTimeRemaining. On completion the quote payload is at data.result.
Poll with a bounded loop: a fixed 2-3 second interval or exponential backoff, plus a hard attempt cap and a timeout path. Never poll without a ceiling.
== 5. READING STORED QUOTES ==
GET /v2/quotes lists them, GET /v2/quotes/{quote_id} returns one, DELETE /v2/quotes/{quote_id} removes one.
Pagination: limit and offset query parameters, default 50, maximum 100. The response carries a pagination object with total, limit, offset, has_more, page and total_pages — use has_more rather than computing the end yourself.
Sorting is one repeatable parameter in field:direction form, e.g. ?sort=created_at:desc.
Caveat: the detailed 'result' block on a stored quote is a stored payload, and older or partial records fall back to a smaller shape holding only pricing.total, pricing.currency, timeEstimation and modelInfo. Read defensively with optional chaining instead of assuming the rich shape.
== 6. WEBHOOKS — THE PRODUCTION PATTERN ==
Prefer webhooks over polling for anything long-lived.
Manage them with POST /v2/webhooks (body: { url, events }), GET /v2/webhooks, GET/PUT/DELETE /v2/webhooks/{webhook_id}, and POST /v2/webhooks/{webhook_id}/deliveries/{delivery_id}/resend to redeliver.
The signing secret is returned ONLY in the create response. Store it immediately; it cannot be read back.
Event catalogue, exhaustively: 'quote.completed', 'quote.failed', 'file.uploaded', 'file.deleted', 'job.status_changed', 'widget.added_to_cart'.
Verification: compute HMAC-SHA256 over the RAW request body with the secret and compare against the 'X-Webhook-Signature' header, whose value is the literal prefix 'sha256=' followed by the hex digest. Use a timing-safe comparison. The event name also arrives in 'X-Webhook-Event'.
Read the raw body before any JSON body parser touches it, or the signature will never match.
Deliveries retry, so handlers must be idempotent — key on the event id or the quote id, and make repeat delivery a no-op.
== 7. THE EMBEDDABLE WIDGET ==
Load /js/quote3d-embed.js, then Quote3D.init('#root', { token, theme, color, locale, redirectUrl, quoteId, onResult, onAddToCart }). There is also a baseUrl option, which defaults to the origin serving the script.
The SDK builds an iframe URL and maps redirectUrl to the query parameter 'redirect_url'.
Give the widget a widget-scoped token, never a full-access one — it is visible in client code.
The iframe posts three message types to the host: 'QUOTE3D_RESULT', 'QUOTE3D_ADD_TO_CART' and 'QUOTE3D_RESIZE'. Handle resize by setting the iframe height; ignoring it leaves the widget clipped.
Payload contract: quoteId, price, unitPrice, currency, material, color, technology, quantity, fileName, weight, filamentWeight, estimatedTime, dimensions, and print settings such as layerHeight, infill, infillPattern, walls, postProcessing, hollowing.
The total is 'price'. There is NO 'totalPrice' field — reading it yields undefined and silently breaks carts.
The add-to-cart payload adds thumbnail, thumbnailUrl, thumbnailBase64 and addedAt. Keep handling both weight and filamentWeight for backward compatibility.
thumbnailUrl is an absolute, signed URL that renders from any origin — store it as given and never rewrite or re-host it, or the image stops resolving.
Do not call the widget's own internal routes from your code. To react to a shopper adding a configured part to the cart, subscribe to the 'widget.added_to_cart' webhook.
== 8. ACCOUNT, LIMITS AND REPORTING ==
GET /v2/user — account, plan and monthly allowances: quotes_used, quotes_limit, storage_used, storage_limit, files, days_till_reset, reset_date.
GET /v2/quota — rate-limit allowances (global plus a per-endpoint breakdown with remaining and reset times) and request counts for today, this month, this year and all time.
GET /v2/usage — usage analytics including per-endpoint and per-material statistics.
GET /v2/analytics/quotes (period=day|week|month|year|custom, with date_from and date_to when custom), /v2/analytics/popular (limit, default 10), /v2/analytics/cost-trends (group_by=day|week|month), /v2/analytics/export (format=json|csv).
== 9. ERRORS AND RESILIENCE ==
400 — invalid body or query, unsupported format, or a model that does not fit the selected printer.
401 — token missing, malformed, expired or revoked.
403 — valid token, not permitted: scope restriction or IP allowlist.
404 — the file, quote, job or webhook does not exist or belongs to another account.
429 — rate limited. Read the 'Retry-After' header and back off exponentially.
500 — retry with backoff; if it persists, surface the timestamp to the user.
Rate-limit state also arrives on successful responses via 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-RateLimit-Reset' and 'X-RateLimit-Window'. Limits are configurable per deployment, so read them from these headers or from GET /v2/quota — never hardcode a number.
== 10. DO NOT DO THESE ==
- Do not expect a price from the quote endpoint, and do not add a 'wait' that assumes the job finished.
- Do not compare job status against uppercase strings.
- Do not treat HTTP 200 on the jobs endpoint as success.
- Do not read 'totalPrice' from a widget payload.
- Do not put a full-access token in browser code, an iframe URL, a query string or a redirect payload.
- Do not JSON-parse the webhook body before computing its signature.
- Do not hardcode rate limits, quota numbers or the file-size cap.
- Do not invent endpoints, fields or query parameters. If this contract does not name it, ask instead of guessing.
== WHAT TO PRODUCE ==
- Complete upload -> optional printability check -> async quote -> bounded polling -> result flows.
- Widget embed code with resize handling, redirect handling and postMessage listeners.
- Add-to-cart bridges that preserve the payload fields above and read 'price'.
- Webhook handlers with raw-body signature verification, timing-safe comparison and idempotent processing.
- Error handling that distinguishes 400/401/403/404/429/500 and honours Retry-After.LLM 上下文,用于小部件集成
您可以要求您的 LLM 助手执行以下小部件相关任务:
- JS SDK 配置:生成使用 token、locale、theme、color、可选的 quoteId 和 redirectUrl 的 Quote3D.init 设置。
- 事件监听:编写宿页监听器,用于监听 QUOTE3D_RESULT、QUOTE3D_ADD_TO_CART 和 QUOTE3D_RESIZE 事件。
- 载荷映射:保存返回的报价载荷字段,如 quoteId、price、unitPrice、currency、technology、quantity、thumbnailUrl、fileName、weight 和 filamentWeight。请注意总价字段是 price,而不是 totalPrice。
Webhook 处理逻辑
提供这些详细信息,以便您的机器人编写 webhook 安全性和事件处理代码:
- 签名验证:编写函数,对原始请求体使用 HMAC-SHA256 验证 X-Webhook-Signature 标头。标头值是字面前缀 sha256= 加上十六进制摘要,因此请使用时间安全比较,而不要用普通的相等判断。
- 事件处理:用幂等的处理函数管理完整的事件目录 - quote.completed、quote.failed、file.uploaded、file.deleted、job.status_changed 和 widget.added_to_cart。
代理最佳实践
在编写 Quote3D 集成代码时,请始终处理以下事项:
- 为报价生成实现异步轮询。不要期望在初始 POST 请求后立即返回价格。
- 在轮询时使用指数退避或固定的 2-3 秒延迟循环
/v2/jobs/{job_id}. - 保留两者
weight&filamentWeight保存在购物车或订单元数据中,以便与当前的小组件载荷和插件保持兼容。 - 对于生产集成,建议使用 Webhooks,并使处理程序具有幂等性,因为可能会发生重试。
关键端点摘要
用于基本实施所需的最常用端点的快速参考索引:
上传文件(服务器端): POST /v2/file
上传文件(浏览器直传,客户端代码中不含令牌): GET /v2/file/upload-id → POST /v2/file/public/{upload_id}
预先检查可打印性: POST /v2/printability/{file_id}
开始报价: POST /v2/file/quote/{file_id}
检查状态: GET /v2/jobs/{job_id}
读取异步作业结果: job.result
获取报价历史: GET /v2/quotes
订阅事件: POST /v2/webhooks
额度与速率限制: GET /v2/user, GET /v2/quota
端到端集成流程
API期望的顺序,以及每一步向下一步交付的内容。请让您的助手实现这六个步骤,而不是孤立地描述某个端点——大多数集成缺陷都源于跳过某一步或对交接内容判断有误。
- 在控制台创建令牌并选择作用域:服务器使用完全访问,嵌入店铺的任何内容使用小组件作用域。
- 把模型送入Quote3D并保存返回的 file_id。可以从后端用 POST /v2/file 上传,或让浏览器通过 GET /v2/file/upload-id 再 POST /v2/file/public/{upload_id} 直传——后一种方式让大文件不经过您的服务器,也让令牌不出现在客户端代码中。
- 可选:用 POST /v2/printability/{file_id} 预先检查模型,在无法打印的几何体消耗报价额度之前将其拒绝。
- 用 POST /v2/file/quote/{file_id} 发起报价。它返回带 jobId 的 202,而不是价格。只发送每次报价中变化的参数,其余项会从控制台配置文件中解析。
- 等待结果。生产环境请订阅 quote.completed 和 quote.failed 这两个Webhook。脚本和原型可以在有限次数的循环中轮询 GET /v2/jobs/{job_id},直到状态为 completed、failed 或 cancelled。
- 从任务载荷读取结果,或稍后通过 GET /v2/quotes 和 GET /v2/quotes/{quote_id} 读取。全程遵循 Retry-After 标头来处理429。
造成大多数集成失效的三个错误: 期望报价端点直接返回价格、把任务状态与大写字符串比较,以及在任务实际已失败时把任务端点返回的HTTP 200当作成功。上面的系统提示词明确指出了这三点,因此您的助手不会重蹈覆辙。