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

# Order boards

> Upload, quote, answer, check out.

The same flow as the [MCP](/mcp/ordering): upload the design, get a live JLCPCB price delivered with shipping, duty and tax, answer anything the files don't state, and send the customer to the checkout link.

## 1. Upload

Send the files with your key. A KiCad project or a Gerber zip; for assembly also a BOM and pick-and-place (KiCad projects make their own); any fabrication drawing, stackup PDF or README goes to ProvenMetal's team.

```bash theme={"system"}
curl https://api.provenmetal.com/v1/uploads \
  -H "X-API-Key: $PROVENMETAL_API_KEY" \
  -F files=@board-gerbers.zip -F files=@bom.csv -F files=@positions.csv
```

```json theme={"system"}
{
  "ok": true,
  "upload_id": "3f2c0b8e9d1a4c6e8f0a1b2c3d4e5f60",
  "upload_url": "https://mcp.provenmetal.com/uploads/3f2c...",
  "files": ["board-gerbers.zip", "bom.csv", "positions.csv"],
  "quote_takes": "The quote tool takes about 5-10 seconds for this upload bare, about 5-60 seconds assembled for its 18-line BOM."
}
```

* A whole project goes up fastest as one `.zip`, or a `.tgz` (unpacked on arrival): `tar -czf - board/ | curl ... -F 'files=@-;filename=upload.tgz'`.
* Each part must be named `files`. Up to 20 files, 50 MB each, 100 MB in all.
* `upload_url` takes more files for two hours with no key (the same multipart form), and `POST /v1/uploads` with no files returns only the link.
* Files are kept six hours after the last one arrives. Treat `upload_id` as a secret: anyone with it can quote the files.

## 2. Quote

```bash theme={"system"}
curl https://api.provenmetal.com/v1/quotes \
  -H "X-API-Key: $PROVENMETAL_API_KEY" -H "content-type: application/json" \
  -d '{
    "upload_id": "3f2c0b8e9d1a4c6e8f0a1b2c3d4e5f60",
    "quantity": 10,
    "assembly": true,
    "project_name": "Motor controller rev B",
    "ship_to": { "name": "Jane Smith", "email": "jane@example.com", "phone": "+1 415 555 0100",
                 "line1": "1 Main St", "city": "Austin", "state": "TX", "postal_code": "78701", "country": "US" }
  }'
```

**201** with an instant price:

```json theme={"system"}
{
  "ok": true, "mode": "instant",
  "quote_id": "9b1d...64 hex",
  "checkout_url": "https://central.provenmetal.com/checkout/9b1d...",
  "total": "$412.30", "total_cents": 41230, "per_board_cents": 4123, "tax_cents": 3050, "currency": "USD",
  "lines": [{ "label": "Bare-board fabrication", "cents": 4560 }, { "label": "Assembly and parts", "cents": 30120 }],
  "lead_time": "3-4 business days", "delivery": "8-12 business days from payment, build included",
  "board": "2-layer 50×40 mm, 1.6 mm FR-4, 1 oz copper, HASL (lead-free), green mask",
  "board_image_url": "https://central.provenmetal.com/...png",
  "delivery_saved": true, "saved_details": false,
  "notes": ["..."], "expires_at": "2026-10-26T00:00:00Z", "next": "Share the checkout link. ..."
}
```

Assembled quotes take seconds when JLCPCB stocks every part and up to about 2.5 minutes when parts are looked up at distributors. If it isn't done within `wait_s` (default 30, at most 150) the answer is **202** with a `request_id` to poll:

```bash theme={"system"}
curl "https://api.provenmetal.com/v1/quote-requests/$REQUEST_ID?wait_s=60" -H "X-API-Key: $PROVENMETAL_API_KEY"
```

Every argument of the MCP [`quote`](/mcp/tools#quote) tool is accepted under the same name: board options (`layers`, `thickness_mm`, `surface_finish`, `solder_mask`, `copper_oz`, `inner_copper_oz`, `material`), advanced fabrication (`jlc_options`, `via_process`, `impedance_controlled`, `jlc_stackup`, `file_stackup`, `separate_boards`), parts (`substitutions`, `customer_supplied_refs`, `do_not_fit_refs`, `staff_picks_parts`), `special_requirements`, `special_notes`, `standard_for_unstated`, `board`, `skip_board_checks`, `board_context` and `itar`. [`GET /v1/capabilities`](/api-reference/checks/board-options-and-services) lists JLCPCB's materials and services.

## 3. Answer what the files don't say

Options are read from the files (ODB++, Gerber job files, Altium reports, the KiCad board's setup). Anything else comes back as **422 `needs_details`**:

```json theme={"system"}
{
  "ok": false, "error": "needs_details",
  "message": "The design files don't say surface_finish.",
  "questions": [{ "option": "surface_finish", "question": "Which surface finish?", "choices": ["hasl_lead_free", "enig"], "usual": "hasl_lead_free" }],
  "known": { "layers": 2 }
}
```

Ask the customer, then send the same quote with the answers (`"surface_finish": "enig"`), or with `"standard_for_unstated": true` if they accept JLCPCB's standard for the rest (1.6 mm, lead-free HASL, 1 oz outer and 0.5 oz inner copper, green, FR-4, no special requirements).

| Answer | What to do |
| - | - |
| `needs_part_numbers` | BOM lines in `parts` name no exact part. Add the part numbers to the BOM and upload again, or pass `staff_picks_parts: true` and ProvenMetal picks them (`picked_parts` in the reply). |
| `off_board_parts` | BOM lines with no pick-and-place position. Pass their references in `do_not_fit_refs` if the customer says to leave them off. |
| `design_files` | A KiCad board with shorts or unrouted connections (each listed), or an option the files state that an instant quote can't build. `skip_board_checks: true` builds a board as designed, only if the customer wants that. |
| `price_unavailable` | Temporary. Try again in a few minutes. |

## 4. Review quotes

`mode: "review"` means ProvenMetal's team quotes it: options JLCPCB's API can't price (`custom_quote_reasons`), or parts that couldn't be priced (`unpriced_parts`, each with why and what was searched). The customer requests the full quote at `checkout_url`. When only the assembly is unpriced, `fabrication_quote` is an instant price for the bare boards with its own checkout link.

An unpriced part may carry a `similar_part` in stock. If the customer approves it, quote again with:

```json theme={"system"}
{ "substitutions": [{ "reference": "U3", "original_mpn": "TPS62130RGTR", "replacement_mpn": "TPS62130ARGTR", "reason": "Customer approved the in-stock variant" }] }
```

Only pass substitutions the customer approved. Passive parts with exact-spec replacements are handled without asking; active parts are never swapped automatically.

## 5. Checkout

Send the customer to `checkout_url`. With a full `ship_to`, delivery is already saved (`delivery_saved: true`) and they only pay; otherwise they enter the rest there. They make their ProvenMetal account when they pay.

When the email in `ship_to` belongs to a returning customer with a saved card and address, the quote says `saved_details: true`. After the customer says yes to buying with them:

<Steps>
  <Step title="Email a code">`POST /v1/quotes/{quote_id}/saved/code`</Step>
  <Step title="Check it">`POST /v1/quotes/{quote_id}/saved/verify` with `{"code": "123456"}`. Show the customer `summary` (total, card, ship-to).</Step>
  <Step title="Pay">`POST /v1/quotes/{quote_id}/saved/pay` with `{"confirm_token": "..."}`. A declined card answers 402 with `checkout_url`.</Step>
</Steps>

## 6. Follow it

```bash theme={"system"}
curl https://api.provenmetal.com/v1/quotes/$QUOTE_ID -H "X-API-Key: $PROVENMETAL_API_KEY"
```

`status` is `quote_ready`, `awaiting_payment`, `sourcing_ready`, `sourcing_requested`, `sourcing_quoted`, `expired`, `ordered`, `in_production` or `shipped`, with `order_ref` once paid and `tracking` once shipped.

<Warning>
  ITAR designs can't be ordered through the API or the MCP: pass `"itar": true` and they are refused before anything is read. Use [provenmetal.com](https://provenmetal.com).
</Warning>


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