ECO Windows · Eco Glass Production
Send glass orders straight from your system — validated against our shape rules, priced live, and booked into production. The same pipeline as the dealer portal, without the clicking.
Ask your ECO Windows representative for an API key. It looks like egp_live_…, is tied to your dealer account and pricing, and is shown to you exactly once — store it in a secret manager. Send it on every request:
Authorization: Bearer egp_live_your_key_here
Payloads use friendly names and codes, not database ids — the same vocabulary as the portal's CSV import. The catalog tells you what exists and what each shape and pane type expects.
curl $BASE/v1/catalog/shapes -H "Authorization: Bearer $KEY" curl $BASE/v1/catalog/pane-types -H "Authorization: Bearer $KEY" curl $BASE/v1/catalog/glass-types -H "Authorization: Bearer $KEY"
POST /v1/quotes runs the full validation + live pricing pipeline and writes nothing. It's your integration playground.
curl -X POST $BASE/v1/quotes \ -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{ "lines": [{ "quantity": 2, "shape": "Rectangle", "dimensions": { "B": "24", "L": "36-1/2" }, "paneType": "Double Pane IG", "glassType": "1/8CL", "spacer": "8TSpacer", "gas": "ARG", "product": "Living Room Left" }] }'
Add your PO number and "validateOnly": true to POST /v1/orders — you get the exact 201 response body back, and nothing is booked.
curl -X POST $BASE/v1/orders \ -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{ "poNumber": "20260825", "orderName": "Smith Residence", "shipDate": "2026-09-15", "lines": [ … ] }' # → HTTP 201 # { "orderId": 104138, "status": "Hold", "totals": { "total": 35.98, … }, … }
The order lands as Hold for office review — exactly like a portal order — and shows up in your portal history. Track it with GET /v1/orders/{id}.
The JSON line is the CSV row, field for field:
| CSV column | JSON field | Notes |
|---|---|---|
| LineNumber | lineNumber | optional — blanks are auto-numbered |
| Quantity | quantity | exploded into one production unit each (A1-1, A1-2…) |
| Shape | shape | name or id from the catalog |
| B, L, R, S, T, U | dimensions | object keyed by letter; which are required depends on the shape |
| PaneType | paneType | name or id |
| GlassType / Laminate / Spacer / Gas | glassType laminate spacer gas | codes or names; every field the pane type accepts is required (gas AIR = no fill) |
| — | fullDescription | optional; generated from the makeup like the portal when omitted |
| Product | product | free text, e.g. the opening's name |
| PoNum / PoItemNum | poNum / poItemNumber | poNum defaults to the header poNumber |
Dimensions are inches and take 24, 24-1/2, or 24 1/2. Minimum side 2″; oversize limits apply per shape.
poNumber is digits-only and must be unique across your estimates and orders — it is your idempotency key. Resubmitting the same PO returns 409 with the existingOrderId, so a retried request can never double-book.
All errors are problem+json. Validation failures return 422 with every problem across all lines in one errors array:
{
"status": 422,
"title": "Validation failed",
"errors": [
{ "lineIndex": 0, "code": "unknown_glass_type", "message": "Glass type 'MIRROR' not recognized. …" },
{ "lineIndex": 1, "lineNumber": "B1", "code": "invalid_dimensions", "message": "Dimensions failed validation …" }
]
}
| Code | Meaning |
|---|---|
| invalid_po_number · missing_po_number | PO must be digits only, and is required on orders |
| missing_ship_date · invalid_ship_date | orders need a shipDate (requested due date), today to two years out |
| duplicate_line_number | two lines share a line number |
| unknown_shape · unknown_pane_type · unknown_glass_type · unknown_laminate · unknown_spacer · unknown_gas | value not in the catalog — check /v1/catalog/* |
| missing_dimension · invalid_dimension · invalid_dimensions | a required letter is missing, unparseable, or fails the shape's geometry / size rules |
| laminate_not_applicable · spacer_not_applicable · gas_not_applicable | the field doesn't apply to that pane type (see its accepts) |
| missing_glass_type · missing_laminate · missing_spacer · missing_gas | every spec the pane type accepts is required — gas AIR means no fill |
| invalid_quantity · missing_lines · too_many_lines | self-explanatory payload problems |
| unpriceable_line · account_not_configured | your account's pricing isn't set up for this makeup — contact ECO Windows; we never book $0 orders |
60 requests/minute per key, 10 order submissions/minute, 200 lines per order. Hitting a limit returns 429 — back off and retry. Need more? Talk to us.