Diamra Developer Docs
All pages

Guide for agents

The rules a coding agent follows when it writes code that talks to a Diamra store. The MCP server gives the agent the same rules as its page guide. Each rule links to the page that has the details, and each group of rules ends with an example.

Three ways to work with a store

  • The API: calls your server makes to the store, at https://api.diamra.com/v1.
  • Webhooks: POSTs Diamra sends your server when something happens in the store.
  • Embed: the design studio in an iframe on the store website, and the messages it sends the page.

Keys and tokens

  • Keep the API key on the server. It starts with dmr_live_. Every key is live, and every call is billed to the store. Never put a key in a web page, a mobile app, a URL or the source code. Read it from an environment variable.
  • Do not ask the developer to paste a key into the chat. Ask for the name of the environment variable that holds it.
  • Send the key in the Authorization header of every call: Bearer and the key.
  • Calls made for a customer also take the customer access token, in the Diamra-Customer-Token header. It comes from Register, Log in or Refresh in Auth. Keep both of the customer tokens on the server, out of URLs and logs.
  • An access token lasts an hour. A refresh token works once, so store the new one from every answer.
The headers of every callJavaScript
// The key and the customer's tokens stay on your server. Read the key from the// environment, and the access token from the session you keep for the customer.const API = "https://api.diamra.com/v1";const headers = {  Authorization: `Bearer ${process.env.DIAMRA_API_KEY}`,  "Diamra-Customer-Token": session.access_token, // from Register, Log in or Refresh  "Content-Type": "application/json",};

Calls

  • Call over HTTPS only. A call over plain HTTP gets a 403 and is never redirected.
  • A design, an estimate and a new set of views take time. The call that starts one answers at once with the status processing and a timing object. Ask again every few seconds. Stop when the status is failed. See Calls that take time.
  • Read an error from its error object. Branch on code, show message, and log the Request-Id header of the response.
  • A 403 plan_required means the store is not on the Retail plan. Tell the developer. Do not retry.
  • Inside /v1 things are only added. Ignore a field you do not know.
A call, its error and the wait for a designJavaScript
// Every call: read an error from its error object, and log the Request-Id header.async function call(path, init) {  const res = await fetch(`${API}${path}`, { headers, ...init });  const body = await res.json();  if (res.ok) return body;  console.error(res.headers.get("Request-Id"), body.error.code, body.error.message);  if (body.error.code === "plan_required") throw new Error("The store is not on the Retail plan."); // do not retry  throw new Error(body.error.message);}// A design takes time. Ask again every few seconds until the status changes.let design = await call("/designs", {  method: "POST",  body: JSON.stringify({ prompt: "A rose gold ring with an oval sapphire" }),});while (design.status === "processing") {  await new Promise((wake) => setTimeout(wake, 3000));  design = await call(`/designs/${design.id}`);}if (design.status === "failed") throw new Error("The design failed."); // stop asking// design.images holds the images, each with its id and link.

Webhooks

  • Check the signature of every delivery before you trust it, on the raw body, with the signing secret of that endpoint. Diamra follows Standard Webhooks, so use a Standard Webhooks library. See Signing keys.
  • Answer a delivery with a 2xx within 15 seconds, then do the work. Diamra sends each event once.
  • Use the webhook-id header to drop a repeat. Ignore an event type or a field you do not know, and still answer with a 2xx.
A delivery, checked with a libraryJavaScript
import express from "express";import { Webhook } from "standardwebhooks";const app = express();const wh = new Webhook(process.env.DIAMRA_WEBHOOK_SECRET); // whsec_...// express.raw keeps the body exactly as it was signed.app.post("/diamra/webhooks", express.raw({ type: "application/json" }), (req, res) => {  let event;  try {    event = wh.verify(req.body, req.headers); // throws on a bad signature or an old timestamp  } catch {    return res.status(400).end();  }  // event.id, event.type, event.data  res.status(200).end();});

Embed

A listener that checks the originJavaScript
const STUDIO_ORIGIN = "https://yourstore.diamra.com";const studio = () => document.querySelector("[data-diamra-store] iframe");window.addEventListener("message", (event) => {  if (event.origin !== STUDIO_ORIGIN) return;  if (event.source !== studio()?.contentWindow) return;  const msg = event.data;  if (!msg || typeof msg.type !== "string") return;  if (!msg.type.startsWith("diamra:")) return;  console.log(msg.type, msg);});

A usual order of work

Sign the customer in (Auth). Upload their photos if they have any (Images). Make a design (Designs). Start a project from the image they pick (Projects). Then add views, measurements and estimates.