Public REST API
The REST API the Mercastra app itself uses, described from the API contract at build time. Endpoint summaries, descriptions and field descriptions come from that contract and are in English only.
Authentication
Requests authenticate with the session cookie the app sets at sign-in. Every request other than a GET must also send the X-CSRF-Token header, echoing the value of the csrf-token cookie.
API keys
A personal API key lets a script or an assistant call the API without a browser session. A key belongs to you, acts as you in exactly one workshop and holds only the scopes you gave it when you created it.
Create one in the app under Account settings → API keys. The full key is shown once, at creation; the app keeps only a hash of it afterwards.
Send the key as a bearer token in the Authorization header. A request authenticated with a key needs no CSRF header.
curl 'https://mercastra.cloud/api/estimates/<estimateId>/revisions' \ -H 'Authorization: Bearer mcr_<publicId>_<secret>'
Scopes
Each scope unlocks the endpoints listed next to it. A write scope includes the matching read scope. Every endpoint that names no scope is session only: it is reachable only by the browser, with the cookie and the CSRF header above.
| Scope | Endpoints |
|---|---|
| estimates:read | |
| estimates:write | |
| orders:read | |
| orders:write |
Expiry and revocation
A key expires 30, 90 or 365 days after it is created, whichever you pick; there is no key that lives forever. You can revoke a key at any time from the same page, and it stops working immediately.
Keys survive a routine password change. A password reset revokes every key you own, and deleting your account deletes them.
In OpenAPI terms
The OpenAPI document declares these security schemes. An operation that lists bearerToken names the scope it needs; one that lists only sessionCookie is session only.
| Scheme | Type | Description |
|---|---|---|
| sessionCookie | apiKey / cookie "session" | The httpOnly session cookie the browser attaches automatically after signing in. Mutating requests (anything but GET, HEAD and OPTIONS) must also send the X-CSRF-Token header echoing the value of the csrf-token cookie, or they are refused with 403. |
| bearerToken | http / bearer | A personal API key, sent as `Authorization: Bearer mcr_...`. A key belongs to one user, acts in exactly one workshop and holds the scopes it was created with; an operation that lists this requirement names the scope it needs, and a write scope implies the matching read scope. Every operation that does not list it is session only. A request authenticated with a key sends no CSRF header. |
Stability
Each endpoint carries one of two stability levels.
- experimental
- May change without notice.
- stable
- Stays as documented.
Endpoints
Every public endpoint, in path order. Each one links to its full description on its resource's page.
- post
/authenticateNo authenticationSign in with email and password - get
/estimates/{estimateId}estimates:readRead an estimate - patch
/estimates/{estimateId}estimates:writeUpdate an estimate's name, recipient, markup or discount - delete
/estimates/{estimateId}estimates:writeDelete an estimate - post
/estimates/{estimateId}/confirmSession onlySnapshot an estimate's current content as a new revision - post
/estimates/{estimateId}/duplicateSession onlyDuplicate an estimate - get
/estimates/{estimateId}/handoffsSession onlyList an estimate's hand-offs - post
/estimates/{estimateId}/handoffsSession onlyRecord that an estimate was handed off to its recipient - post
/estimates/{estimateId}/line-itemsSession onlyAdd a line item to an estimate - patch
/estimates/{estimateId}/line-items/{lineItemId}Session onlyUpdate a line item - delete
/estimates/{estimateId}/line-items/{lineItemId}Session onlyRemove a line item - get
/estimates/{estimateId}/pdf-exportsSession onlyList an estimate's PDF exports - post
/estimates/{estimateId}/pdf-exportsSession onlyGenerate a PDF export of an estimate - get
/estimates/{estimateId}/pdf-exports/{pdfExportId}Session onlyDownload a PDF export's bytes - delete
/estimates/{estimateId}/pdf-exports/{pdfExportId}Session onlyDelete a PDF export - get
/estimates/{estimateId}/revisionsestimates:writeList an estimate's revisions - get
/filesSession onlyList files in a category and scope - post
/filesSession onlyUpload a file - get
/files/{fileId}Session onlyDownload a file's bytes - get
/grids/{gridId}Session onlyRead a grid - patch
/grids/{gridId}Session onlyRename a grid or change its icon size - delete
/grids/{gridId}Session onlyDelete a grid - post
/grids/{gridId}/buttonsSession onlyAdd a button to a grid - patch
/grids/{gridId}/buttons/{buttonId}Session onlyUpdate a button - delete
/grids/{gridId}/buttons/{buttonId}Session onlyRemove a button - post
/grids/{gridId}/duplicateSession onlyDuplicate a grid - post
/logoutSession onlyEnd the caller's session - get
/meSession onlyRead the signed-in account's profile - patch
/meSession onlyUpdate the signed-in account's profile - get
/me/data-exportSession onlyExport everything stored about the account - get
/orders/{orderId}orders:readRead an order - patch
/orders/{orderId}Session onlyUpdate an order's title, customer name or notes - patch
/orders/{orderId}/statusorders:writeChange an order's status - get
/predefined-itemsSession onlyList the catalog of predefined grid items, domains and templates - get
/workshopsSession onlyList the caller's workshops - patch
/workshops/{workshopId}Session onlyUpdate the workshop's profile - put
/workshops/{workshopId}/contextSession onlyReplace the workshop's context notes - get
/workshops/{workshopId}/entitlementsSession onlyRead the workshop's plan entitlements and quota usage - get
/workshops/{workshopId}/estimatesestimates:readList a workshop's estimates - post
/workshops/{workshopId}/estimatesestimates:writeCreate an estimate in a workshop - get
/workshops/{workshopId}/estimates/most-used-line-itemsestimates:readList the workshop's most-used line items - delete
/workshops/{workshopId}/grid-icons/{fileId}Session onlyDelete a grid button icon - get
/workshops/{workshopId}/gridsSession onlyList a workshop's grids - post
/workshops/{workshopId}/gridsSession onlyCreate a grid in a workshop - get
/workshops/{workshopId}/ordersorders:readList a workshop's orders - post
/workshops/{workshopId}/ordersorders:writeCreate an order in a workshop
Schemas
The named shapes a field's type links to: every entity and model, documented once on its own page.
Validation errors
Every endpoint that validates its request body answers a 400 with the same shape.
Sent with status 400 when the request body does not match the endpoint's schema. Each issue names the offending path and says what is wrong with it.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
| status | string | Yes | const: "fail" | - |
| message | array of object | Yes | - | - |
| message[].path | array of string | number | Yes | - | - |
| message[].message | string | Yes | - | - |