---
title: "Fill in a Trust Profile with an agent - Trooth"
description: "Instructions for an AI agent that fills in and keeps current a company's Trust Profile on Trooth, for the company's owner. Follow them in order. Every step is an HTTPS request; nothing needs a browser."
canonical_url: "https://trooth.co/docs/agents/fill-trust-profile"
markdown_url: "https://trooth.co/docs/agents/fill-trust-profile.md"
generated_from: "the rendered page, converted to Markdown when this was requested"
agent_index: "https://trooth.co/llms.txt"
---

# Fill in a Trust Profile with an agent

Instructions for an AI agent that fills in and keeps current a company's Trust Profile on Trooth, for the company's owner. Follow them in order. Every step is an HTTPS request; nothing needs a browser.

Written for agents. People preparing a profile themselves can read [Prepare your Trust Profile for buyers](https://trooth.co/docs/prepare-trust-profile).

## What you need

- An agent key from the workspace's owner or admin. It starts with `tra_` and is usually in the environment variable `TROOTH_AGENT_KEY`. The owner creates it in API keys, Agent keys. Send it on every request as `Authorization: Bearer $TROOTH_AGENT_KEY`.
- The key's permission: `profile:read` reads, `profile:write` also changes the draft, `profile:publish` also puts the draft on the public page. `GET /api/v1/profile` tells you which permission your key has.
- The base address `https://trooth.co/api/v1`. Requests and answers are JSON; send `Content-Type: application/json`.

## Over MCP instead

If your agent connects to MCP servers, it can do every step below with four tools on Trooth's MCP server, `https://api.trooth.co/public/mcp` (streamable HTTP). Add the agent key to the MCP connection as the HTTP header `Authorization: Bearer tra_...`; the server forwards it only to the trooth.co profile API, for the call it came with, and never stores or logs it. An OAuth sign-in is not an agent key and is never sent there.

- `trooth_profile_get`, no arguments: the draft, its `revision`, whether it is published and its public address. Needs profile:read.
- `trooth_profile_checklist`, no arguments: what is left, and who does it. Needs profile:read.
- `trooth_profile_update`: `changes` (the same list as the PATCH body below), and optionally `if_match` (the revision you read), `idempotency_key` and `dry_run`. Needs profile:write. A write without your own `idempotency_key` gets one, returned in the answer; retry with it.
- `trooth_profile_publish`, no arguments: put the draft live. Needs profile:publish.

Each tool answers with what trooth.co answered, unchanged: the same results, codes and fixes as the routes below, in `structuredContent.response`. With no key, the answer has status `unauthenticated` and says how to add one. The rules, the reading order and the error table on this page apply to both.

## With a browser agent, no key needed

An agent that drives Chrome (Claude in Chrome, ChatGPT agent, Gemini in Chrome) can fill in, edit and publish the profile in the same editor a person uses, with no API key and no MCP connection.

1. A person signs in to trooth.co first. An agent never types a password, a sign-in code or a CAPTCHA; those stay with the person.
2. Open `https://trooth.co/dashboard/public-page`. Every section has its own address (for example `#edit-intro`), every box has a visible label joined to it, and every control has a name the accessibility tree reads.
3. In a Chrome that supports WebMCP the editor also offers named tools, so the agent calls a function instead of hunting for boxes: `trooth_profile_read`, `trooth_profile_field_catalog`, `trooth_profile_update_fields`, `trooth_profile_save_draft` and, while the workspace allows its agent to publish, `trooth_profile_publish`.
4. Save the draft to keep changes; the public page changes only when the draft is published. The same rules hold as for the API: a source for every fact, nothing the company does not publish.
5. A first publish needs the owner to prove the company's domain. The editor says so and links to the page that does it; tell the owner and continue with the rest.

## The loop

1. Read what is left: `GET /api/v1/profile/checklist`. Each task says whether it is yours (agent) or a person's, and whether it is done.
2. Read every field you can write, its type, its allowed values and what it means: `GET /api/v1/profile/schema` (JSON Schema). Field names are case-sensitive. Fields marked `x-trooth-human-only` are not yours.
3. Read the draft as it is now: `GET /api/v1/profile`. Keep the `revision` it returns; it is also the ETag.
4. Read the company's own pages (the list below) and note, for each field, the value, the page address and the exact words that say it.
5. Check your changes without saving: `PATCH /api/v1/profile` with `"dry_run": true`. Fix every rejected change.
6. Save them: the same request without `dry_run`, with an `Idempotency-Key` header (any unique string, reused only to retry the same request) and `If-Match` set to the revision you read.
7. Read every result. `applied` carries `stored`, the value the profile now holds: check it matches what you sent. `rejected` carries `code`, `message` and `fix`: do what `fix` says and send that change again.
8. Repeat for each section until `GET /api/v1/profile/checklist` shows every agent task done. Hand each person task to the owner with its link. Publish if your key may (`POST /api/v1/profile/publish`), or tell the owner the draft is ready.

## Rules that keep the record true

1. Set only what the company itself publishes, on its own website or in a public registry. Never infer, estimate, summarize into a new claim, or fill a gap from what is typical for companies like it.
2. Give every value its source: the https address of the page and the exact words on it. A value with no source is refused. Trooth keeps each source beside the change it supports.
3. When the company does not publish something, answer it, do not guess it: send `"state": "not_published"` (or `"not_applicable"`) with a one-sentence reason saying what you checked.
4. Keep the company's wording. Do not add adjectives, marketing or your own judgment. Write dates as YYYY-MM-DD and addresses as full https links.
5. Do not remove or replace a value a person entered unless the company's own page now says otherwise; when you do, cite that page.
6. Never write text addressed to an AI model into a field. A record that reads as instructions is held for a person and cannot be published by an agent (code `held_for_review`).
7. Trooth's own observations (witnessed facts) are not yours to write; they come from Trooth's readings. You write what the company declares.
8. If a step needs a person, stop that step, tell the owner exactly what to do and give the link, and carry on with everything else.

## Where to read, and what it fills

Read these pages on the company's own domain, in this order. Each fills the fields named; the schema has the full list.

1. Home and About: `/name`, `/tagline`, `/description`, `/website`, `/founded`, `/hq`, `/founders`, `/socials`.
2. Legal imprint, terms and public registries: `/legalName`, `/registration`, `/companyType`, `/ownership`.
3. Security or Trust page and security.txt: `/security` (contact, authentication, encryption, penetration tests, disclosure policy) and `/trustCards`.
4. Privacy policy and data processing agreement: `/privacy`, `/dataSafety`.
5. Sub-processor list: `/relationships` (each sub-processor, its purpose and location).
6. AI or responsible-AI page, model cards: `/aiFeatures`, `/modelCards`.
7. Pricing, plans and procurement pages: `/pricing`, `/procurement`, `/buyer`.
8. Status page, documentation and developer pages: `/hosting`, `/developerSurfaces`, `/links`.

## A change, and its answer

Each change names one field by its JSON Pointer (RFC 6901): `/tagline`, `/security/contact`, `/founders/0/name`. `/founders/-` adds to the end of a list; `"op": "remove"` clears a field or removes a list item. Up to 200 changes per request; they apply in order, and a rejected one does not stop the rest.

```bash
curl -X PATCH https://trooth.co/api/v1/profile \
  -H "Authorization: Bearer $TROOTH_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2e70-security-1" \
  -H 'If-Match: "2026-10-21T09:14:03.120000Z"' \
  -d '{
  "changes": [
    { "path": "/tagline", "value": "Trust Profiles every buyer can check",
      "source": { "url": "https://trooth.co/", "quote": "Trust Profiles every buyer can check" } },
    { "path": "/security/contact", "value": "security@trooth.co",
      "source": { "url": "https://trooth.co/security", "quote": "Report a vulnerability to security@trooth.co" } },
    { "path": "/founders/-", "value": { "name": "D'Andre Heggie", "title": "Founder" },
      "source": { "url": "https://trooth.co/about", "quote": "D'Andre Heggie, Founder" } },
    { "path": "/security/pentestPerformedAt", "state": "not_published",
      "reason": "https://trooth.co/security does not mention a penetration test." }
  ]
}'
```

The answer lists one result per change, in order, and the new revision.

```json
{
  "saved": true,
  "applied": 4,
  "rejected": 0,
  "results": [
    { "path": "/tagline", "status": "applied", "stored": "Trust Profiles every buyer can check" },
    { "path": "/security/contact", "status": "applied", "stored": "security@trooth.co" },
    { "path": "/founders/0", "status": "applied", "stored": { "name": "D'Andre Heggie", "title": "Founder" } },
    { "path": "/security/pentestPerformedAt", "status": "applied", "stored": null }
  ],
  "revision": "2026-10-21T09:15:40.882000Z"
}
```

A rejected change looks like this, and nothing about it was saved:

```json
{ "path": "/securty/contact", "status": "rejected", "code": "unknown_field",
  "message": "The Trust Profile has no field called \"securty\".",
  "fix": "Use a field from GET /api/v1/profile/schema; field names are case-sensitive." }
```

## Logo, cover and photos

Set `/logoUrl`, `/coverUrl` or a founder's `photoUrl` to a direct https link to a PNG, JPEG or WebP image on the company's own site. Trooth copies the image once and serves its own copy; it never links to the original. A logo needs at least 512 by 512 pixels. If the image is refused (`artwork_rejected`, `logo_too_small`), leave it to a person.

## Publish

Every write changes the draft, as the editor's Save does; the public page does not change. With `profile:publish`, `POST /api/v1/profile/publish` puts the draft live. It needs the workspace's agent publishing permission on and, the first time, the company's domain proved by a person. An answer of `human_action_required` names the task and its link.

## What only a person does

These steps are refused to an agent on purpose. Hand them to the owner and continue:

- Proving the company controls its domain (a DNS TXT record), in Trust Profile, Domain.
- Choosing the page address, colors and heading font.
- Counsel's review marks.
- Turning the agent publishing permission on or off, and creating or revoking agent keys.
- Signing in, two-factor authentication and anything about the person's own account.

Say it in one sentence with the link from the task, for example: "To put the page live, prove you control trooth.co here: https://trooth.co/dashboard/public-page?tab=domain. Everything else is done." Then check `GET /api/v1/profile/checklist` again when the owner says it is done.

## Every answer that is not a success

Errors are JSON problem details (RFC 9457): `code` names what happened and `fix` says what to do. Per-change refusals come back inside `results` with the same fields.

| Code | What to do |
| --- | --- |
| `unauthenticated` | The key is missing, mistyped or revoked. Ask the owner for a new agent key. |
| `insufficient_scope` | The key lacks the permission this needs. Ask the owner for a key with the permission named in needed. |
| `invalid_request` | The body is not the shape described above. Read issues, fix the JSON and send again. |
| `invalid_path` | The path is not a JSON Pointer. Start it with a slash: /security/contact. |
| `unknown_field` | No such field. Check the spelling against the schema; names are case-sensitive. |
| `human_only` | A person keeps this field. Leave it; it is on the person's task list if it matters. |
| `source_required` | Add source with the https address and the quoted words, or answer the field as not_published. |
| `reason_required` | A not_published or not_applicable answer needs a one-sentence reason. |
| `value_required` | Send value, or a not_published answer. |
| `not_accepted` | The field did not keep the value: wrong type, a value outside its allowed set, or an item missing a field it needs. Read the field in the schema and send a value of that type. |
| `index_out_of_range` | That list position does not exist. Read the profile again; use /field/- to add. |
| `not_a_list` | The field is not a list, so nothing can be added to it. Set it instead. |
| `malformed_text` | Remove the NUL or broken character and send again. |
| `name_required` | Set /name first, in the same request or before it. |
| `nothing_applied` | Every change was refused; fix each one by its fix. Nothing was saved. |
| `revision_changed` | Someone saved in between. Read the profile again, check your changes still apply, send them with the new revision. |
| `idempotency_mismatch` | The Idempotency-Key was used for a different request. Use a new key for new changes. |
| `artwork_rejected` | The image could not be fetched or used. Give a direct link to the image file, or leave it to a person. |
| `logo_too_small` | The logo is under 512 by 512 pixels. Find a larger one on the company's site, or leave it to a person. |
| `cover_too_small` | The cover is under the minimum size. Use a larger image, or leave it to a person. |
| `domain_taken` | Another company claims that website's domain. Do not change /website; tell the owner. |
| `slug_taken` | The page address the name produces is taken. Tell the owner to choose the address. |
| `human_action_required` | A person has to do the step named in task, at action_url. Tell the owner, then try again after. |
| `held_for_review` | Fields named in fields read as instructions to a model. Rewrite them as plain statements, or leave publishing to a person. |
| `transcript_required` | A product video needs its transcript before it is published. Add the transcript or remove the video. |
| `website_required` | Set /website before publishing. |
| `no_profile` | There is no profile yet. Write one, starting with /name. |
| `rate_limited` | Too many requests. Wait a minute and retry with the same Idempotency-Key. |
| `storage_unavailable` | A temporary failure; nothing changed. Retry shortly with the same Idempotency-Key. |
| `workspace_suspended` | The workspace is suspended. Stop and tell the owner. |

## Endpoints

- `GET /api/v1/profile`: the draft, its revision, whether it is live, your key's permission. Needs profile:read.
- `PATCH /api/v1/profile`: change fields. Needs profile:write. Headers: Idempotency-Key, If-Match.
- `POST /api/v1/profile/publish`: put the draft live. Needs profile:publish.
- `GET /api/v1/profile/checklist`: what is left, and who does it. Needs profile:read.
- `GET /api/v1/profile/schema`: every writable field. No key needed.
- MCP: `trooth_profile_get`, `trooth_profile_checklist`, `trooth_profile_update` and `trooth_profile_publish` on `https://api.trooth.co/public/mcp`, with `Authorization: Bearer tra_...` on the MCP connection.

## Was this page helpful?

## Structured data

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://trooth.co/#org",
      "name": "Trooth",
      "legalName": "Trooth, LLC",
      "alternateName": [
        "Trooth, LLC",
        "Trooth Network",
        "trooth.co"
      ],
      "url": "https://trooth.co",
      "logo": {
        "@type": "ImageObject",
        "@id": "https://trooth.co/#logo",
        "url": "https://trooth.co/brand/trooth-mark_black-on-white_1024.png",
        "contentUrl": "https://trooth.co/brand/trooth-mark_black-on-white_1024.png",
        "width": 1024,
        "height": 1024,
        "caption": "Trooth"
      },
      "image": {
        "@id": "https://trooth.co/#logo"
      },
      "description": "Trooth is an infrastructure and cybersecurity company providing Machine-Readable Trust. The Trooth Network keeps one current Machine-Readable Trust Profile per company, each fact sourced. Trooth signs what it witnessed; company declarations are unsigned.",
      "foundingDate": "2025-12-16",
      "address": {
        "@type": "PostalAddress",
        "streetAddress": "777 Brickell Ave, Suite 500, PMB 1174",
        "addressLocality": "Miami",
        "addressRegion": "FL",
        "postalCode": "33131",
        "addressCountry": "US"
      },
      "contactPoint": {
        "@type": "ContactPoint",
        "contactType": "customer support",
        "email": "hello@trooth.co",
        "url": "https://trooth.co/contact"
      },
      "sameAs": [
        "https://x.com/Troothllc",
        "https://github.com/troothllc",
        "https://www.crunchbase.com/organization/trooth",
        "https://www.wikidata.org/wiki/Q141292994",
        "https://www.youtube.com/@Troothllc",
        "https://www.trustpilot.com/review/trooth.co"
      ]
    },
    {
      "@type": "WebSite",
      "@id": "https://trooth.co/#website",
      "url": "https://trooth.co",
      "name": "Trooth",
      "alternateName": "Trooth Network",
      "inLanguage": "en",
      "publisher": {
        "@id": "https://trooth.co/#org"
      },
      "sameAs": [
        "https://trooth.co/network/company/trooth"
      ],
      "potentialAction": {
        "@type": "SearchAction",
        "target": {
          "@type": "EntryPoint",
          "urlTemplate": "https://trooth.co/network?q={search_term_string}"
        },
        "query-input": "required name=search_term_string"
      }
    },
    {
      "@type": "ItemList",
      "@id": "https://trooth.co/#sitelinks",
      "name": "Trooth sitelinks",
      "itemListElement": [
        {
          "@type": "SiteNavigationElement",
          "position": 1,
          "name": "Join Trooth for free",
          "url": "https://trooth.co/signup"
        },
        {
          "@type": "SiteNavigationElement",
          "position": 2,
          "name": "Company, Trooth",
          "url": "https://trooth.co/network/company/trooth"
        },
        {
          "@type": "SiteNavigationElement",
          "position": 3,
          "name": "Trooth Network",
          "url": "https://trooth.co/network"
        }
      ]
    }
  ]
}
```
