> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thewo.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Report contract

> Understand the Operational Evidence report request, response, and supported vocabulary.

# Report contract

Operational Evidence converts submitted evidence into a normalized operational
report.

## Endpoint

```http theme={null}
POST /v1/evidence/reports
```

The endpoint is synchronous in the current MVP.

A successful request returns:

```http theme={null}
201 Created
```

with a completed report.

## Request headers

| Header            | Required | Description                                                         |
| ----------------- | -------- | ------------------------------------------------------------------- |
| `content-type`    | Yes      | Must be `application/json`.                                         |
| `x-api-key`       | Yes      | Secret API credential used to authenticate the integration.         |
| `Idempotency-Key` | No       | Client-generated key used to make create retries safely idempotent. |

See Authentication for API key handling rules.

## Idempotent retries

Evidence Report creation supports the optional `Idempotency-Key` request header.

```http theme={null}
Idempotency-Key: report-request-123
```

Use a unique client-generated key for each logical report-creation request.

Retrying the same normalized request with the same key returns the original
successful Evidence Report result without creating another report, retrieving
remote images again, invoking the report provider again, or consuming another
usage unit.

Do not reuse one key for different requests.

```text theme={null}
same key + same request
→ original result

same key + different request
→ 409 idempotency_conflict

same key while original request is processing
→ 409 idempotency_in_progress
```

Keys must contain between 1 and 255 characters after trimming.

Requests without `Idempotency-Key` remain supported but do not receive the
safe-retry guarantee.

## Rate limiting

Evidence Report creation is protected by technical rate limiting.

Rate limiting is separate from monthly quota:

* rate limiting protects API capacity and abusive request patterns;
* quota controls commercial operation consumption during the current quota period.

When the technical request limit is exceeded, the API returns:

```text theme={null}
429 rate_limit_exceeded
```

A rate-limit response includes a `Retry-After` header indicating how many
seconds the client should wait before retrying.

Safe retry metadata may also be included in `error.details`, including:

* `limit`;
* `remaining`;
* `resetAt`;
* `retryAfterSeconds`.

Clients should follow `Retry-After` instead of immediately retrying the
request.

Concrete rate-limit values are endpoint/runtime configuration and should not be
inferred from monthly quota.

## Request body

The request body contains:

| Field                   | Type   | Required      | Description                                          |
| ----------------------- | ------ | ------------- | ---------------------------------------------------- |
| `context`               | string | Yes           | Operational context used to interpret the evidence.  |
| `language`              | string | No            | Nonblank language guidance for the generated report. |
| `evidence`              | object | Yes           | Evidence submitted for analysis.                     |
| `evidence.text`         | string | Conditional   | Nonblank textual evidence.                           |
| `evidence.images`       | array  | Conditional   | Image evidence references.                           |
| `evidence.images[].url` | string | Yes per image | Absolute HTTP or HTTPS image URL.                    |

`evidence` must contain either:

* nonblank text;
* at least one image;
* or both.

An empty evidence object is invalid.

## Strict request contract

The public HTTP request is strict.

Unknown request properties are rejected rather than silently ignored.

Image entries are also strict objects containing:

```json theme={null}
{
  "url": "https://example.com/evidence.jpg"
}
```

The current public contract does not accept an image URL as a bare array
string.

Image URLs must:

* be absolute;
* use `http` or `https`;
* be nonblank.

## Remote image retrieval

Image URL validation at the HTTP boundary is only the first step.

When image evidence is present, The Wo retrieves each remote image through the
shared secure remote-resource boundary before the report provider is invoked.
The remote-resource boundary applies target validation, controlled redirect
handling, a bounded timeout, maximum-content-size enforcement, and content-type
validation.

The current Operational Evidence image policy accepts:

```text theme={null}
image/jpeg
image/png
image/gif
image/webp
```

The provider receives the validated image content rather than the original
customer-controlled URL. The original URL remains part of the submitted Evidence
Report input, but it is not delegated to the provider for an independent network
fetch.

The relevant execution order is:

```text theme={null}
authentication
→ technical rate limit
→ idempotency decision
→ monthly quota
→ secure remote image retrieval
→ report provider
→ persistence
→ Usage
```

Quota is therefore checked before The Wo performs remote image retrieval.
An idempotent replay returns the original completed report without retrieving the
remote image again.

A remote image that cannot be safely accepted returns:

```text theme={null}
422 remote_evidence_image_rejected
```

A remote image that cannot currently be retrieved safely returns:

```text theme={null}
503 remote_evidence_image_unavailable
```

These public failures do not expose private DNS results, blocked addresses,
redirect targets, socket details, or raw network errors.

## Language

`language` is optional.

When provided, it must be a nonblank string.

The current MVP does not expose a fixed public language whitelist.

Integrations should use recognizable language tags such as:

* `en`
* `en-US`
* `pt-BR`
* `es`

When language is omitted, the report generation flow can use the language of
the submitted evidence.

## Successful response

A successful create operation returns the following public fields.

| Field                      | Type           | Description                                      |
| -------------------------- | -------------- | ------------------------------------------------ |
| `id`                       | string         | Evidence Report identifier.                      |
| `status`                   | string         | Current public create response status.           |
| `result`                   | object         | Generated operational result.                    |
| `result.title`             | string         | Concise report title.                            |
| `result.description`       | string         | Structured description of the observed evidence. |
| `result.category`          | string         | Controlled operational category.                 |
| `result.priority`          | string         | Suggested operational priority.                  |
| `result.suggestedNextStep` | string or null | Suggested follow-up action when available.       |
| `result.tags`              | string\[]      | Operational search or classification tags.       |
| `result.riskFlags`         | string\[]      | Detected uncertainty or risk indicators.         |
| `result.confidence`        | number         | Confidence value from 0 through 1.               |
| `usage`                    | object         | Usage associated with the completed operation.   |
| `usage.operation`          | string         | Billing/usage operation identifier.              |
| `usage.units`              | number         | Units consumed by this operation.                |

For the current synchronous create endpoint:

* `status = completed`
* `usage.operation = evidence_report`
* `usage.units = 1`

The public response intentionally does not expose:

* customer identifiers;
* API key identifiers;
* provider credentials;
* provider request identifiers;
* raw provider responses;
* model configuration;
* prompt contents;
* persistence metadata;
* provider cost.

## Supported contexts

The current public contexts are:

| Value                   | Intended operational use                          |
| ----------------------- | ------------------------------------------------- |
| `property_maintenance`  | Property and facility maintenance evidence.       |
| `delivery_confirmation` | Delivery-related operational evidence.            |
| `field_inspection`      | Evidence collected during field inspections.      |
| `damage_report`         | Evidence describing observed damage.              |
| `inventory_check`       | Evidence collected during inventory verification. |

Unsupported contexts are rejected by the public request validator.

Because context is validated at the HTTP contract boundary, an unsupported
context results in a `400 invalid_request_payload` response.

New contexts are product decisions and must be introduced intentionally.

## Supported priorities

Generated reports use one of the following priority values:

* `low`
* `medium`
* `high`
* `urgent`

Priority is generated from the submitted evidence.

Clients do not submit priority as part of the create request.

The value is a suggested operational urgency and should be interpreted
together with the report description, risk flags, and confidence.

## Supported categories

The current controlled category vocabulary is:

* `plumbing`
* `electrical`
* `cleaning`
* `security`
* `elevator`
* `structural`
* `appliance`
* `other`

The initial category vocabulary originated with property maintenance and is
currently the controlled category set accepted by the Operational Evidence
domain.

Categories may evolve into context-specific vocabularies as additional
operational contexts mature.

Clients should therefore consume the category as a documented API value and
avoid building assumptions that prevent future documented values from being
introduced.

## Unsupported category behavior

`category` is not part of the create request.

It is generated by the report generation flow.

If generated output contains a category that cannot be represented by the
current domain contract, the generated report is rejected instead of exposing
an unsupported value.

The current HTTP behavior for invalid generated output is:

```text theme={null}
502 invalid_generated_report
```

## Provider independence

The endpoint contract is owned by The Wo.

A customer integrates with:

```text theme={null}
The Wo public contract
```

not with the concrete AI provider behind the operation.

Provider-specific models, prompt structures, SDK responses, credentials, and
errors are not part of the public API contract.

## Related guides

* [Quickstart](/operational-evidence/quickstart)
* [Authentication](/platform/authentication)
* [Usage and quotas](/operational-evidence/guides/usage-and-quotas)
* [Errors](/operational-evidence/guides/errors)
* [TypeScript integration](/operational-evidence/examples/typescript)
