> Machine-readable EthicsPortal resources — Markdown content negotiation, llms.txt, sitemaps, agent card and skills index — plus the SAML 2.0 and SCIM 2.0 integration surfaces, and an explicit list of what EthicsPortal does not publish.

Source: https://ethicsportal.eu/el/developers/
Updated: 2026-08-24

---

# EthicsPortal for developers

EthicsPortal is delivered as hosted SaaS, not as an API product. This page is the
stable index of everything a developer, a procurement script, or an AI agent can
fetch or integrate against — and an equally explicit list of what does not exist,
so nobody spends an afternoon looking for it.

Last updated: 2026-08-22.

---

## Markdown content negotiation

Every page on `ethicsportal.eu` is published twice: as HTML for browsers and as
Markdown for agents. Two ways to reach the Markdown:

- Append `.md` to any page URL — `https://ethicsportal.eu/product.md`
- Request the HTML URL with an `Accept: text/markdown` header

```bash
curl -sI -H "Accept: text/markdown" https://ethicsportal.eu/product/
# content-type: text/markdown; charset=utf-8
# vary: Accept
```

Negotiation follows [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#name-accept)
and the [acceptmarkdown.com](https://acceptmarkdown.com/) convention:

- Quality values are honoured, and a media type marked `q=0` is never served.
- `406 Not Acceptable` is returned, with a plain-text list of the available
  representations, when neither HTML nor Markdown is acceptable to the client.
- `Vary: Accept` is set on every negotiated response, so a CDN cannot hand the
  HTML variant to an agent that asked for Markdown.
- HTML responses advertise their twin twice: a `Link` header with
  `rel="alternate"; type="text/markdown"`, and a `<link rel="alternate">` in the
  document head.

A request with no `Accept` header, or with `Accept: */*`, gets HTML.

## Machine-readable files

| Resource | URL | Contents |
| --- | --- | --- |
| Agent guide | `/agents.md` | Stable index of agent-facing resources |
| LLM summary | `/llms.txt` | Structured site overview, per language |
| Full content | `/llms-full.txt` | Every page's text in one file |
| Agent card (A2A) | `/.well-known/agent-card.json` | Agent-to-Agent capability card |
| Agent skills index | `/.well-known/agent-skills/index.json` | Skills manifest, v0.2.0 |
| Compliance-lookup skill | `/.well-known/agent-skills/whistleblower-compliance/SKILL.md` | The one published skill |
| Sitemap | `/sitemap.xml` | Sitemap index, one entry per language |
| Crawl policy | `/robots.txt` | Crawl rules and sitemap pointer |
| Security contact | `/.well-known/security.txt` | Vulnerability disclosure address |
| Vendor questionnaire | `/caiq-ethicsportal.csv` | CAIQ v4 answers as CSV |
| Blog feed | `/blog/index.xml` | RSS |

Every one of these is served from the apex domain and is stable. Link to them
directly rather than scraping the pages that describe them.

## Not-found responses

A URL that does not exist returns a real `404` — never a `200` carrying an
application shell. A client that asked for Markdown gets the `404` with a
Markdown body listing the sitemap, `llms.txt`, and this page, so an agent that
guessed a URL can recover without parsing an error page.

## Integration surfaces

The reporting channel itself is operated at `secure.ethicsportal.eu`, and its
integration surfaces are identity standards rather than a product API. Both are
configured per organization from organization settings, and both are included in
the single plan — see [pricing](/pricing/).

### SAML 2.0 single sign-on

| Setting | Value |
| --- | --- |
| SP entity ID | `https://secure.ethicsportal.eu/auth/saml/metadata` |
| SP metadata | Same URL, served as XML |
| Assertion consumer service (ACS) | `https://secure.ethicsportal.eu/auth/saml/callback` |
| Binding | HTTP-POST |
| NameID | Email address |

One service provider serves every tenant; the organization is resolved from the
in-flight sign-in, so there is no per-organization ACS URL to configure. Okta,
Microsoft Entra ID, and any other SAML 2.0 identity provider work. SSO can be
enforced for one or more verified email domains, with optional just-in-time
provisioning of members on first sign-in.

### SCIM 2.0 provisioning

| Setting | Value |
| --- | --- |
| Base URL | `https://secure.ethicsportal.eu/scim/v2` |
| Authentication | Bearer token, generated and rotated in organization settings |
| Resource | `/Users` — list, read, create, replace, update, deactivate |
| Media type | `application/scim+json` |

The bearer token identifies the organization, so the base URL is the same for
every tenant. `DELETE /Users/{id}` deprovisions by deactivating the member,
closing their access to reports while keeping case history attributable.

## What EthicsPortal does not publish

Stated plainly, because the absence is a design decision and not an oversight:

- **No public REST or GraphQL API.** Reports are not readable or writable
  programmatically. Confidentiality of a disclosure is the product's core
  obligation under EU Directive 2019/1937, and a general-purpose API is a second
  path to the same data.
- **No MCP server.** The public resources above are the machine interface.
- **No SDK packages.** There is no API surface to wrap.
- **No outbound webhooks.** Case notifications are delivered by email to handlers.
- **No programmatic report submission.** Disclosures are made by a human through
  the organization's own reporting channel.

Agents should treat `ethicsportal.eu` as a reference source — EU whistleblower
law by member state, penalties, and product facts — and not as an operational
endpoint.

## Contact

- Integration and product questions: support@ethicsportal.eu
- Vulnerability disclosure: security@ethicsportal.eu, or see
  [`/.well-known/security.txt`](/.well-known/security.txt)
