devguard

Trust Center

Publish your compliance posture as JSON and build your own public trust page.

Overview

The Trust Center exposes a curated, read-only view of your organization's compliance posture over a single public JSON endpoint. You choose exactly what to publish here: selected frameworks with their status, subprocessors, and downloadable certificates. Any website can fetch it and render a live "here's the compliance we fulfil" page. Any surrounding prose (an intro, disclosures, data-processing notes) is authored on your own site around this data.

devguard provides the API only. There is no hosted page and no embeddable widget: you fetch the URL and build the page in your own site, with your own branding. The payload contains no branding; it is pure compliance data.

Two rules define the whole surface:

  • Nothing is public unless you explicitly add it and enable the Trust Center.
  • The response is a strict field allowlist. Internal data (risk scores, owners, storage keys, per-control coverage) never crosses the wire.

Endpoint

GET https://app.devguard.ch/api/trust/{publicId}
  • No authentication. The data is public by design, and the response allows any origin (Access-Control-Allow-Origin: *) so you can call it directly from a browser.
  • {publicId} is an opaque, rotatable handle (e.g. trust_a1B2c3...) shown on this page. Rotating it immediately revokes the old URL.
  • Disabled or unknown handles return 404, indistinguishably, so the endpoint never reveals that a not-yet-public Trust Center exists.
  • Responses carry a short Cache-Control (max-age=60, stale-while-revalidate=300) and are rate-limited per IP.

Response shape

{
  "generatedAt": "2026-07-15T09:30:00.000Z",
  "frameworks": [
    {
      "id": "b7f1...",
      "name": "ISO 27001",
      "identifier": "ISO27001",
      "identifierColor": "#3b82f6",
      "version": "2022",
      "displayMode": "badge",
      "status": "on_track"
    },
    {
      "id": "c3a2...",
      "name": "SOC 2",
      "identifier": "SOC2",
      "identifierColor": "#8b5cf6",
      "version": "Type II",
      "displayMode": "certified",
      "certified": {
        "body": "Prescient Assurance",
        "date": "2026-03-01",
        "certificateItemId": "e5d4..."
      }
    }
  ],
  "subprocessors": [
    {
      "id": "d4c3...",
      "name": "Amazon Web Services",
      "website": "https://aws.amazon.com",
      "description": "Cloud infrastructure hosting.",
      "category": "CLOUD",
      "relationship": "SUB_PROCESSOR",
      "location": "AWS eu-central-2, Zürich"
    }
  ],
  "certificates": [
    {
      "id": "e5d4...",
      "title": "SOC 2 Type II Report",
      "documentKind": "SOC2",
      "issuedAt": "2026-03-01T00:00:00.000Z",
      "expiresAt": "2027-03-01T00:00:00.000Z",
      "downloadable": true,
      "downloadPath": "/api/trust/trust_a1B2c3.../certificate/e5d4..."
    }
  ]
}

The payload is a generatedAt timestamp plus three arrays — frameworks, subprocessors, and certificates. generatedAt is when the response was produced (accurate to the short cache window); show it as a "last updated" signal. Wrap the rest in your own page layout and copy.

Frameworks

Each framework carries a displayMode that controls what detail is exposed:

displayModeExtra fieldMeaning
badgestatusA status label only: completed, on_track, or in_progress.
percentagecompletionAn integer 0–100 coverage percentage.
certifiedcertifiedA manual assertion (body, date) decoupled from computed coverage, optionally tied to a published certificate via certificateItemId.

A framework below the "in progress" threshold is never published in badge or percentage mode, so you can render any framework you receive with confidence. Use the framework's own identifierColor as a local accent (a chip, a meter fill, a seal), never as text on a filled background, so contrast holds whatever color the API returns.

Subprocessors

relationship is one of PROCESSOR or SUB_PROCESSOR. location is the location name only (never a full address). description is present only when you chose to publish it.

Certificates

Expired certificates are omitted automatically. When downloadable is true, the object includes a relative downloadPath. Prefix it with the same origin you fetched the payload from:

GET https://app.devguard.ch{downloadPath}

This mints a fresh, short-lived presigned URL per request and 302-redirects to it, so a plain link works. The download responds only while the Trust Center is enabled and the certificate is marked downloadable; otherwise it returns 404. The underlying storage key is never exposed.

Documents on request

A downloadable certificate also carries access. With "PUBLIC" it has a downloadPath as above. With "ON_REQUEST" it has no downloadPath; instead it has a requestPath and, if you pasted one, nda with the text and a version. devguard provides no default NDA.

Your page shows a request form and posts it to the request path:

POST https://app.devguard.ch{requestPath}
Content-Type: application/json

{ "itemId": "<certificate id>", "name": "…", "email": "…", "company": "…",
  "ndaAccepted": true, "ndaVersion": "<nda.version>", "website": "" }

ndaAccepted and ndaVersion are required when the certificate has an NDA, and the version must match the current one. Keep website as a hidden, empty field: a request that fills it is dropped. A stored request answers 202. The endpoint sends the requester nothing. Requests are limited per IP address and per email address; the limit is counted per server instance, so it is a ceiling against abuse, not an exact quota.

Admins see the request under Download requests at the top of this page and approve or deny it by hand. On approval devguard emails the requester one link to GET /api/trust/{publicId}/download/{token}. The link opens a page with a Download button, so a mail scanner that opens the link uses up nothing; only the button press counts. The link works for 7 days and 3 downloads, and each download is logged with its time and IP address. The token is stored only as a hash. An admin can revoke an approved link at any time. A request whose NDA changed after it arrived cannot be approved. Requests, with the requester's name, email, company, NDA acceptance and downloads, are deleted 12 months after they arrive, so the download log covers the last 12 months only.

Recreate this page yourself

Open Preview above and switch to the Source code tab for a single, self-contained React component that fetches the API and renders the response: the same three arrays, mapped into markup you can style yourself. Copy it out and swap in your own header, brand and surrounding copy.

The steps below walk through how it works.

1. Fetch the payload

const API = 'https://app.devguard.ch';
const PUBLIC_ID = 'trust_a1B2c3...';

const res = await fetch(API + '/api/trust/' + PUBLIC_ID);
if (!res.ok) {
  // 404 = not published, disabled, or wrong handle
  throw new Error('Trust Center is not available');
}
const trust = await res.json();

2. Render frameworks by display mode

Each framework is one of three shapes. Branch on displayMode:

trust.frameworks.map((f) => {
  if (f.displayMode === 'badge') return renderStatusPill(f.status);
  if (f.displayMode === 'percentage') return renderMeter(f.completion);
  return renderCertified(f.certified.body, f.certified.date);
});

For a certified framework you can tie the claim to its downloadable proof: find the certificate whose id matches f.certified.certificateItemId and link to API + cert.downloadPath.

3. Render certificates

Every certificate is listed. downloadable decides whether there is anything to fetch, and access decides how: a PUBLIC certificate gets a download link, an ON_REQUEST one gets the request form described under Documents on request. Expired certificates are already removed, so you don't filter them yourself. downloadPath is relative, so prefix it with the API origin.

4. Render subprocessors

A flat list, ideal for a table. relationship is PROCESSOR or SUB_PROCESSOR; location is a name only; description is present only when you chose to publish it.

Everything else, from your logo and brand color to hero copy, data-region facts and footer, is yours to author around this data. Because the endpoint is CORS-enabled, the same fetch runs unchanged in the browser.

Enabling the Trust Center

  1. Add the frameworks, subprocessors, and certificates you want to publish (admins only).
  2. Use the Preview to confirm exactly what will be exposed.
  3. Toggle Public on and share the API URL with your site.

Publishing certificates

Add certificate uploads a document or publishes one already uploaded elsewhere in devguard. Choose its Type (SOC 2, ISO 27001, Penetration Test, DPA, AOC, Business associate agreement (HIPAA), or Other), give it a Title, and set Issued at and Valid until. Valid until is the last day you want to share the document; once it has passed, the certificate drops out of the API on its own.

Each published certificate has a Downloadable switch. Off, the certificate is listed but cannot be fetched. On, an Access select appears beside it:

  • Public: anyone with the API URL can download it.
  • On request: a visitor asks for it through your page's request form, and an admin decides.

A SOC 2 report is usually meant for restricted use, which is the case On request serves. An on-request certificate also gets an NDA button. Paste your own NDA under Your NDA text (optional), or leave it empty; devguard provides none. Saving a changed text makes it a new version, and requests from then on must accept that version.

Handling download requests

Requests arrive under Download requests at the top of this page. Each pending request shows the requester's name, email and company, the document, the date it arrived, and whether they accepted the NDA (NDA accepted with the date, or No NDA).

  • Approve sends the requester an email, Your download from your organization's name, with one link. The link works for 7 days and 3 downloads.
  • Deny closes the request. devguard sends the requester nothing.

Decided requests move under Decided, with who decided and when; an approved one also shows how many of its downloads have been used. Revoke link stops the link at once. A request whose NDA changed after it arrived cannot be approved: deny it and ask the requester to send a new one.

How is this guide?

On this page