Developers

The BUSE API

Everything the website does, you can do from code or from an agent: upload a file, get the price the checkout will charge, place and pay the order.

  • 01Session cookie
  • 02JSON envelopes
  • 03Pages as Markdown

01Overview

What it is

BUSE prints parts in FDM in Agadir and delivers anywhere in Morocco, delivery included in every price.

The API is the one the website itself uses. Prices are computed on the server from the uploaded file's geometry: a client only chooses the material SKU, the finish, the quantity and whether the order is rushed, never a price, a volume or a weight.

The flow is: sign in (or sign up) → `POST /api/upload` the STL/OBJ/3MF → `POST /api/quotes/batch` to price a basket → `POST /api/addresses` → `POST /api/orders` → `POST /api/payments/checkout` for a Stripe Checkout URL. Every response is a JSON envelope `{ success, data }` or `{ success: false, error: { code, message, details } }`.

Every public HTML page also answers in Markdown with `Accept: text/markdown`; the site index for agents is /llms.txt.

02Authentication

Sign in, then send the cookie

Accounts are email and password (better-auth). The sign-in response sets a session cookie; send it back on every call. There are no API keys yet.

# 1. Sign in (keeps the session cookie in cookies.txt)
curl -c cookies.txt -H 'Content-Type: application/json' \
  -d '{"email":"you@example.com","password":"..."}' \
  https://buse.ma/api/auth/sign-in/email

# 2. Upload the file; the key is what every pricing call takes
curl -b cookies.txt -F file=@part.stl https://buse.ma/api/upload

# 3. Price the basket as the order will charge it
curl -b cookies.txt -H 'Content-Type: application/json' \
  -d '{"items":[{"fileKey":"uploads/<you>/<key>","filename":"part.stl","materialId":"mat_pla_white","quantity":2}]}' \
  https://buse.ma/api/quotes/batch

03Endpoints

Every endpoint

Generated from the same validators the server enforces. Request bodies and the error codes are in the OpenAPI document.

Auth

Email + password sessions (better-auth). The session is a cookie; send it back on every call.

MethodPathWhat it doesAuth
POST/api/auth/sign-up/emailCreate an accountEmail, password and name. A verification email is sent; the session cookie is set once verified.Public
POST/api/auth/sign-in/emailSign inSets the `better-auth.session_token` cookie on success. Keep the cookie jar for the calls below.Public
GET/api/auth/get-sessionCurrent sessionNull when not signed in.Session
POST/api/auth/sign-outSign outEnds the session.Session

Catalog

Materials and delivery destinations.

MethodPathWhat it doesAuth
GET/api/materialsMaterial catalogEvery in-stock colour SKU with its price per gram. Public.Public
GET/api/shipping/destinationsDelivery citiesType-ahead on the cities we deliver to; the id is what an address's `shippingDestinationId` takes. Rate limit: 60 per minute per client.Session

Quotes

Upload a file, price it, save a devis.

MethodPathWhat it doesAuth
POST/api/uploadUpload a 3D fileMultipart form with one `file` field: STL, OBJ or 3MF, up to 50 MB. The returned `key` is what every pricing call takes as `fileKey`; it lives in the caller's own namespace. Rate limit: 20 per minute per client.Session
GET/api/uploadUpload limitsAccepted extensions and the size cap.Session
POST/api/analyzeAnalyse a file and price one copyGeometry (volume, bounding box, printability) plus a quote in the given SKU. A part that does not fit the 256 mm bed, is too small or is not a closed mesh is a 400 with `details.reason`. Rate limit: 20 per minute per client.Session
POST/api/quotes/calculatePrice one fileThe price of one line: SKU, finish, quantity, rush. `isRush` is refused with `reason: rushUnavailable` when the print does not fit a working day. Rate limit: 60 per minute per client.Session
POST/api/quotes/batchPrice a basketThe total an order will charge: lines, the per-order service fee, the order minimum, the plate credit and delivery (included). Always price a basket here rather than summing single lines. Rate limit: 60 per minute per client.Session
POST/api/quotesSave a devisSaves the basket as a numbered quote (DV-YYYY-NNNN), valid for a week, re-priced from the files. Rate limit: 20 per minute per client.Session
GET/api/quotesList my devisThe caller's saved quotes.Session
GET/api/quotes/{id}A devisWith its lines.Session
PATCH/api/quotes/{id}Update a devisIts status. Rate limit: 5 per minute per client.Session
DELETE/api/quotes/{id}Delete a devisAnd its lines.Session
GET/api/quotes/{id}/pdfThe devis as PDFRe-priced from the files; `application/pdf`.Session

Orders

Addresses, orders, payment, invoices.

MethodPathWhat it doesAuth
GET/api/addressesMy addressesThe caller's delivery addresses. Rate limit: 60 per minute per client.Session
POST/api/addressesAdd an address`shippingDestinationId` must be an id from /api/shipping/destinations; an unknown city is refused with `reason: cityNotServed`. Rate limit: 20 per minute per client.Session
PATCH/api/addresses/{id}Edit an addressThe caller's own. Rate limit: 20 per minute per client.Session
DELETE/api/addresses/{id}Remove an addressThe caller's own. Rate limit: 20 per minute per client.Session
POST/api/ordersPlace an orderPriced again from the files on the server; the response total is what Stripe will charge. `acceptTerms` must be `true`. The order is created unpaid; pay it through /api/payments/checkout. Rate limit: 20 per minute per client.Session
GET/api/ordersMy ordersThe caller's orders, newest first.Session
GET/api/orders/{id}/invoiceThe invoice PDFIssued when the order was paid; 404 before.Session
POST/api/payments/checkoutPay an orderReturns a Stripe Checkout URL for the order's total, in MAD. The order turns `paid` when Stripe confirms, never from the client. Rate limit: 20 per minute per client.Session

Projects

Work the instant quote cannot price: a human quote.

MethodPathWhat it doesAuth
POST/api/requestsSubmit a custom projectFor work the instant quote cannot price: a part to reproduce from photos, a batch nobody has modelled. A human answers with a quote. Rate limit: 5 per minute per client.Session
GET/api/requestsMy project requestsThe caller's requests.Session

Cards

The 3D-printed business card generator.

MethodPathWhat it doesAuth
POST/api/cardsPrice a business cardText and style choices only; the mesh is generated and priced on the server. Rate limit: 20 per minute per client.Session

Account

Profile and contact.

MethodPathWhat it doesAuth
PATCH/api/user/profileUpdate my profileName and phone. Rate limit: 20 per minute per client.Session
POST/api/contactWrite to the workshopSends an email to the team. Public. Rate limit: 5 per minute per client.Public

04Errors

Every error is JSON

Validation failures list the fields; business rules name a reason (rushUnavailable, cityNotServed, exceedsBuildVolume, meshNotClosed); unknown routes answer the same envelope with a hint.

{ "success": false,
  "error": { "code": "VALIDATION_ERROR",
             "message": "Validation failed",
             "details": { "errors": [{ "field": "items.0.materialId", "message": "..." }] } } }

Build on it

The document is the contract. Something missing? Tell us.