API
Send a file and a configuration and we'll return the price straight away: 3D printing and acrylic (PMMA) laser cutting. It's the same engine that calculates prices on the website, so any agreed rates are applied automatically.
Getting started
You need an account and a key. Create the key from Account → API keys. It is shown only once: we don't store it in plain text, so if you lose it you'll need to revoke it and create another one.
Everything uses HTTPS and returns JSON. Requests with a body expect JSON with Content-Type: application/json; requests with a file use multipart.
To check that the key works, any endpoint will do:
curl https://haztupieza.es/api/v1/orders \
-H "Authorization: Bearer htp_TU_CLAVE"Get a quote
Getting a quote is free and creates nothing: no saved quote, no cart and no order. You can call it repeatedly while adjusting dimensions.
With a file
POST/api/v1/quotes/file
The quick way: upload the part and we measure it for you. It works for 3D printing and laser cutting; the process is inferred from the file extension.
3D printing — an STL, a 3MF or a STEP:
curl https://haztupieza.es/api/v1/quotes/file \
-H "Authorization: Bearer htp_TU_CLAVE" \
-F "file=@soporte.stl" \
-F 'config={"materialId":"pla","colorId":"negro","qualityId":"standard","infillId":"i25","quantity":4,"supports":true,"leadTimeId":"standard"}'Laser cutting — an SVG or a DXF. The dimensions come from the drawing itself:
curl https://haztupieza.es/api/v1/quotes/file \
-H "Authorization: Bearer htp_TU_CLAVE" \
-F "file=@tapa.svg" \
-F 'config={"sheetId":"pmma-colada-incoloro-3","quantity":10,"leadTimeId":"standard"}'The response includes what we measured, as well as the price:
{
"ok": true,
"errors": [],
"total": 24.18,
"breakdown": {
"unitPrice": 6.045,
"lines": [
{ "id": "material", "label": "Material", "amount": 4.12 },
{ "id": "machine", "label": "Máquina", "amount": 11.4 },
{ "id": "finishing", "label": "Acabados", "amount": 4.9 }
],
"taxRate": 0.21,
"leadTimeDays": 3
},
"file": {
"name": "soporte.stl",
"mesh": {
"volumeCm3": 18.42,
"surfaceCm2": 96.3,
"boundingBoxMm": { "x": 62.4, "y": 41, "z": 18 },
"triangles": 24680,
"watertight": true,
"hash": "9f2c1a7b"
}
}
}We don't keep the file. It is measured in memory and then discarded. If we can't open the format —SolidWorks, Illustrator— the response is 200 with «manualReview» set to true and the reason: a person will quote it.
With the geometry already measured
POST/api/v1/quotes
If you already have the part volume and bounding box —because you measure it yourself or saved them from an earlier quote— you can skip uploading the file.
curl https://haztupieza.es/api/v1/quotes \
-H "Authorization: Bearer htp_TU_CLAVE" \
-H "Content-Type: application/json" \
-d '{
"process": "FDM_3D",
"label": "soporte.stl",
"config": {
"materialId": "pla",
"colorId": "negro",
"qualityId": "standard",
"infillId": "i25",
"quantity": 4,
"supports": true,
"leadTimeId": "standard"
},
"mesh": {
"volumeCm3": 18.42,
"surfaceCm2": 96.3,
"boundingBoxMm": {
"x": 62.4,
"y": 41,
"z": 18
},
"triangles": 24680,
"watertight": true,
"hash": "9f2c1a7b"
}
}'A 200 doesn't always mean yes. When the part can't be made —that sheet is no longer available, the size doesn't fit the machine— the response is still 200 with «ok» set to false and the reason in «errors». It's a response, not a failure: retrying would give exactly the same result. Always check «ok».
Laser cutting, all fields
Without a file, you can request any shape from the catalogue. This example includes everything the endpoint accepts, with the default values shown; almost nothing is required.
curl https://haztupieza.es/api/v1/quotes \
-H "Authorization: Bearer htp_TU_CLAVE" \
-H "Content-Type: application/json" \
-d '{
"process": "LASER_ACRYLIC",
"label": "frontal",
"config": {
"sheetId": "pmma-colada-incoloro-3",
"shape": "ROUNDED_RECT",
"shapeId": "rounded-rect",
"shapeParams": {
"w": 300,
"h": 200,
"radius": 12
},
"widthMm": 300,
"heightMm": 200,
"cornerRadiusMm": 12,
"innerDiameterMm": 0,
"quantity": 10,
"cutouts": [
{
"id": "ventana",
"shapeId": "circle",
"params": {
"d": 22
},
"xMm": 60,
"yMm": 100,
"rotationDeg": 0,
"conservarPieza": true
},
{
"id": "ranura",
"shapeId": "stadium",
"params": {
"w": 40,
"h": 8
},
"xMm": 240,
"yMm": 100,
"rotationDeg": 90
},
{
"id": "rotulo",
"shapeId": "texto",
"params": {},
"texto": {
"texto": "SALIDA",
"tipografiaId": "stardos-stencil",
"alturaMm": 25
},
"xMm": 150,
"yMm": 100,
"rotationDeg": 0
}
],
"holes": {
"pattern": "CORNERS",
"diameterMm": 4,
"edgeDistanceMm": 10,
"count": 4,
"edgeCounts": [
2,
2,
2,
2
],
"rows": 0,
"columns": 0,
"centerDistanceMm": 0,
"points": []
},
"engraveAreaCm2": 0,
"leadTimeId": "express",
"vectorPendingReview": false,
"notes": "Cantos pulidos por la cara vista."
}
}'Only these are required: sheetId, shape, widthMm, heightMm, quantity, leadTimeId
shapeId: "texto" — cuts the text as the outline of the part, using the font and height you specify.
curl https://haztupieza.es/api/v1/quotes \
-H "Authorization: Bearer htp_TU_CLAVE" \
-H "Content-Type: application/json" \
-d '{
"process": "LASER_ACRYLIC",
"config": {
"sheetId": "pmma-colada-incoloro-3",
"shape": "CUSTOM",
"shapeId": "texto",
"texto": {
"texto": "ABIERTO",
"tipografiaId": "anton",
"alturaMm": 80
},
"widthMm": 400,
"heightMm": 80,
"quantity": 2,
"leadTimeId": "standard"
}
}'3D printing, all fields
The same for FDM: the long example, including the optional fields.
curl https://haztupieza.es/api/v1/quotes/file \
-H "Authorization: Bearer htp_TU_CLAVE" \
-F "file=@pieza.3mf" \
-F 'config={"materialId":"pla","colorId":"negro","qualityId":"standard","infillId":"i25","quantity":4,"supports":true,"leadTimeId":"standard","finishIds":["sanding"],"extraColorIds":["rojo"],"plateId":"auto","nozzleId":"auto","pauses":[{"layer":40,"action":"Colocar 4 tuercas M3 en los alojamientos","inserts":[{"optionId":"tuerca-m3","quantity":4}]}],"notes":"La cara buena es la de arriba."}'Options
The identifiers accepted by «materialId», «sheetId» and the rest. This list comes from the same catalogue the workshop uses and changes when the catalogue changes: don't copy it, request it.
Everything below, in one call and always up to date:
GET/api/v1/catalog
curl https://haztupieza.es/api/v1/catalog \
-H "Authorization: Bearer htp_TU_CLAVE"And this is how it looks today:
Materials (3D printing)
| Identifier | Name | Details |
|---|---|---|
| pla | PLA | PLA · 15 colores |
| pla-alta-resistencia | PLA alta resistencia | PLA · 9 colores |
| pla-mate | PLA Mate | PLA · 3 colores |
| pla-reciclado | PLA Reciclado | PLA · 3 colores |
| pla-seda | PLA Silk | PLA · 7 colores |
| pla-madera | PLA Madera | PLA · 3 colores |
| pla-marmol | PLA Marmol | PLA · 2 colores |
| pla-glitter | PLA Glitter | PLA · 4 colores |
| pla-fluorescente | PLA Fluorescente (glow in the dark) | PLA · 2 colores |
| pla-metalizado | PLA Metalizado | PLA · 4 colores |
| petg | PETG | PETG · 7 colores |
| abs | ABS-E | ABS · 5 colores |
| asa | ASA | ASA · 4 colores |
| tpu-95a | TPU 95A Flex | TPU · 5 colores |
| nylon-pa | Nylon PA | PA · 2 colores |
| hips | HIPS | HIPS · 2 colores |
Each material includes its colours in «colors». The colour ID goes in «colorId».
Qualities
| Identifier | Name | Details |
|---|---|---|
| draft | Borrador 0,28 mm | 0.28 mm |
| standard | Estándar 0,20 mm | 0.2 mm |
| fine | Fina 0,16 mm | 0.16 mm |
| ultra | Ultrafina 0,12 mm | 0.12 mm |
Infill options
| Identifier | Name | Details |
|---|---|---|
| i15 | 15 % ligero | 15 % |
| i25 | 25 % estándar | 25 % |
| i40 | 40 % resistente | 40 % |
| i60 | 60 % robusto | 60 % |
| i100 | 100 % macizo | 100 % |
Acrylic (PMMA) sheets (laser cutting)
| Identifier | Name | Details |
|---|---|---|
| pmma-colada-incoloro-3 | Metacrilato transparente 3 mm | 3 mm · 1000×600 mm |
| pmma-colada-incoloro-5 | Metacrilato transparente 5 mm | 5 mm · 1000×600 mm |
| pmma-colada-incoloro-6 | Metacrilato transparente 6 mm | 6 mm · 1000×600 mm |
| pmma-colada-incoloro-8 | Metacrilato transparente 8 mm | 8 mm · 1000×600 mm |
| pmma-colada-incoloro-10 | Metacrilato transparente 10 mm | 10 mm · 1000×600 mm |
| pmma-extrusion-incoloro-3 | Metacrilato extrusión transparente 3 mm | 3 mm · 1000×600 mm |
| pmma-extrusion-incoloro-5 | Metacrilato extrusión transparente 5 mm | 5 mm · 1000×600 mm |
| pmma-blanco-3 | Metacrilato opal 3 mm | 3 mm · 1000×600 mm |
| pmma-negro-3 | Metacrilato negro 3 mm | 3 mm · 1000×600 mm |
| pmma-tintado-3-rojo | Metacrilato tintado rojo 3 mm | 3 mm · 1000×600 mm |
| pmma-tintado-3-azul | Metacrilato tintado azul 3 mm | 3 mm · 1000×600 mm |
| pmma-tintado-3-verde | Metacrilato tintado verde 3 mm | 3 mm · 1000×600 mm |
| pmma-tintado-3-ambar | Metacrilato tintado ámbar 3 mm | 3 mm · 1000×600 mm |
| pmma-tintado-3-fume | Metacrilato tintado fumé 3 mm | 3 mm · 1000×600 mm |
| dm-3 | DM 3 mm | 3 mm · 800×400 mm |
| pmma-fluor-3-naranja | Metacrilato fluorescente naranja 3 mm | 3 mm · 1000×600 mm |
| pmma-fluor-3-rojo | Metacrilato fluorescente rojo 3 mm | 3 mm · 1000×600 mm |
| pmma-fluor-3-verde | Metacrilato fluorescente verde 3 mm | 3 mm · 1000×600 mm |
Catalogue shapes
| Identifier | Name | shapeParams |
|---|---|---|
| rect | Rectángulo | w, h |
| rect-bevel | Rectángulo achaflanado | w, h, bevel |
| rect-corner | Rectángulo con esquina cortada | w, h, cutW, cutH |
| rect-slant | Rectángulo con lado inclinado | w, hLeft, hRight |
| separador | Separador de estantería | w, h, frente |
| triangle | Triángulo | w, h |
| triangle-right | Triángulo rectángulo | w, h |
| triangle-right-mirror | Triángulo rectángulo invertido | w, h |
| trapezoid | Trapecio | wTop, wBottom, h |
| parallelogram | Paralelogramo | w, h, offset |
| hexagon | Hexágono | w, h |
| octagon | Octágono | w, h, bevel |
| polygon | Polígono regular | sides, d |
| rounded-rect | Rectángulo redondeado | w, h, radius |
| circle | Círculo | d |
| ring | Corona | d, inner |
| oval | Óvalo | w, h |
| stadium | Óvalo plano | w, h |
| semicircle | Semicírculo | d |
| quarter-circle | Cuarto de círculo | r |
| arch | Arco | w, h |
| barrel | Tonel | w, h, bulge |
| star | Estrella | points, d, inner |
| heart | Corazón | w, h |
| drop | Gota | w, h |
| arrow | Flecha | w, h, stem, head |
| kite | Cometa | w, h, cross |
| gem | Gema | w, h, crown, top |
«shapeId» selects the shape and «shapeParams» passes its dimensions, which are different for each one. Neither is needed with a file or a custom rectangle.
Hole patterns
| Identifier | Name | Details |
|---|---|---|
| NONE | Sin agujeros | — |
| CORNERS | En las esquinas | diameterMm, edgeDistanceMm |
| PERIMETER | Repartidos por el borde | diameterMm, edgeDistanceMm, count o edgeCounts |
| RADIAL | En círculo | diameterMm, count, centerDistanceMm |
| GRID | En cuadrícula | diameterMm, rows, columns, centerDistanceMm |
| POINTS | En coordenadas concretas | diameterMm, points[{ xMm, yMm }] |
| CUSTOM | Los que traiga el archivo | — |
Lead times
| Identifier | Name | Details |
|---|---|---|
| standard | Estándar | 3 días laborables |
| express | Exprés 48 h | 2 días laborables |
| urgent | Urgente 24 h | 1 días laborables |
File formats
Formats we accept, and what we do with each one:
| Identifier | Proceso | Details |
|---|---|---|
| .stl .obj .3mf .ply | FDM_3D | Se miden solas. Precio al momento. |
| .step .stp .iges .igs .brep | FDM_3D | Se teselan en el servidor. Precio al momento. |
| .sldprt .ipt .f3d .3dm .sat .x_t | FDM_3D | CAD propietario: lo cotiza una persona. |
| .svg .dxf | LASER_ACRYLIC | Se miden solas. Precio al momento. |
| .ai | LASER_ACRYLIC | Lo cotiza una persona. |
Orders
GET/api/v1/orders
The latest fifty, newest first, with their status and tracking.
GET/api/v1/orders/{code}
One specific order, with its lines and amounts.
{
"order": {
"code": "HTP-3MQ8N-LY45L",
"status": "IN_PRODUCTION",
"total": 43.05,
"trackingCarrier": "MRW",
"trackingNumber": "0123456789",
"items": [
{ "label": "tapa.svg", "quantity": 10, "process": "LASER_ACRYLIC",
"unitPrice": 3.55, "total": 35.5 }
]
}
}Possible statuses are: AWAITING_PAYMENT, PAID, IN_PRODUCTION, QUALITY_CHECK, READY_FOR_PICKUP, SHIPPED, DELIVERED, CANCELLED, REFUNDED
Request limit
60 requests per minute and key. Every response tells you how many you have left, so you don't need to hit the limit to know where it is:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 42If you go over, you get a 429 with «Retry-After» in seconds. It's not a punishment: quoting builds the geometry of the part and checks the stock, and a badly closed loop can leave everyone else without service.
When something goes wrong
Always a JSON with «code» —stable, so you can make decisions from it— and «error», which is the message to read.
401unauthorized— the key is missing, invalid or has been revoked.404not_found— that order isn't yours. We return the same response if it doesn't exist; otherwise it could be used to find out which codes exist.422invalid_request— the configuration is invalid. It includes «details» field by field.429rate_limited— you've exceeded the limit.
For assistants and agents
If you're integrating this into an assistant: with the customer's key and a file, you can get a quote in a single call, with no previous steps and without uploading anything anywhere first.
There is a machine-readable description in two formats:
- /openapi.json — the full contract, for generating a client or loading it as a tool.
- /llms.txt — a short plain-text summary to put into context.
What isn't available yet
Place an order. You can get a quote, but you can't buy yet. We first need to agree how payment will work —invoice, credit— and that's a conversation, not an endpoint. If you're interested, write to us and we'll talk: it's one step away from being ready.
Missing something, or does something not work as described here? Tell us. The person who wrote it will reply.