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

# Verify a Response

> Fetch the attestation report and the signed receipt for a real response, then check the signatures and hashes yourself.

This guide walks through verifying one response end to end: confirm the gateway is an attested
TEE workload, then confirm the signed receipt binds your exact request and response to it. You only
need `curl`, `jq`, and `openssl`. Full TEE quote verification additionally needs a DCAP verifier
library, noted where it applies.

For the concepts behind each step, see [How Confidential AI works](/confidential-ai/how-it-works).

## Prerequisites

```bash theme={null}
export API_KEY="your-redpill-api-key"
export BASE="https://api.redpill.ai"
```

## 1. Fetch the attestation report with a fresh nonce

```bash theme={null}
export NONCE="$(openssl rand -hex 16)"
curl -s "$BASE/v1/aci/attestation?nonce=$NONCE" \
  -H "Authorization: Bearer $API_KEY" -o report.json

jq '{api_version, workload_id, workload_keyset_digest,
     signing_address,
     report_data: .attestation.report_data,
     stale_after: .attestation.freshness.stale_after,
     provenance: .attestation.source_provenance}' report.json
```

Check that:

* `api_version` is `aci/1`.
* `attestation.freshness.stale_after` is in the future.
* `attestation.report_data` is derived from your `NONCE` and the keyset (a DCAP verifier confirms the
  quote and this binding). See [Attestation report](/confidential-ai/attestation-report).
* `attestation.source_provenance` matches the gateway release you trust.

<Note>
  Verifying `attestation.evidence.quote` against Intel DCAP collateral, and the keyset endorsement,
  requires a verifier library. The platform publishes verifier tooling; this guide covers the checks you can
  reproduce with shell tools. The `workload_id`, `workload_keyset_digest`, freshness, and signature
  checks below do not need DCAP.
</Note>

## 2. Make a request and capture the receipt id

```bash theme={null}
curl -s -D headers.txt "$BASE/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"qwen/qwen3-30b-a3b-instruct-2507",
       "messages":[{"role":"user","content":"Explain attestation in one sentence."}]}' \
  -o response.json

export RECEIPT_ID="$(grep -i '^x-receipt-id' headers.txt | tr -d '\r' | awk '{print $2}')"
echo "receipt: $RECEIPT_ID"
```

Save `response.json`; its bytes are what the receipt commits to.

## 3. Fetch the signed receipt

`GET /v1/aci/receipts/{id}` returns the bare canonical receipt:

```bash theme={null}
curl -s "$BASE/v1/aci/receipts/$RECEIPT_ID" \
  -H "Authorization: Bearer $API_KEY" -o receipt.json

jq '{receipt_id, workload_id, workload_keyset_digest, endpoint}' receipt.json
```

## 4. Confirm the receipt belongs to the attested gateway

The receipt must come from the same workload you attested in step 1:

```bash theme={null}
test "$(jq -r .workload_id report.json)" = "$(jq -r .workload_id receipt.json)" \
  && test "$(jq -r .workload_keyset_digest report.json)" = "$(jq -r .workload_keyset_digest receipt.json)" \
  && echo "workload matches" || echo "MISMATCH"
```

## 5. Check the bound hashes

The `event_log` records the request and response hashes. Confirm the response hash matches the bytes
you received:

```bash theme={null}
RESP_HASH="sha256:$(sha256sum response.json | awk '{print $1}')"
RECEIPT_RESP_HASH="$(jq -r '.event_log[] | select(.type=="response.returned") | .wire_hash' receipt.json)"
echo "received: $RESP_HASH"
echo "receipt:  $RECEIPT_RESP_HASH"
```

These match when the response was not altered after the gateway signed it. The
`request.received.body_hash` event records the gateway-observed request body (for an
[E2EE](/guides/e2ee-encryption) request, that is the decrypted body).

## 6. Verify the signature

The receipt's `signature` covers the canonical receipt bytes. Verify it with the official verifier
helper, which confirms the signature under a `receipt_signing_keys` entry from the attested keyset:

```bash theme={null}
# Conceptual: use the published verifier to check the receipt signature
# against a receipt_signing_keys entry in the attested keyset from step 1.
```

A receipt signed by a key that the attested keyset does not endorse is not bound to the attested
workload, and verification fails.

## 7. Read the upstream verification result

```bash theme={null}
jq '.event_log[] | select(.type=="upstream.verified")
    | {provider, model_id, result, required, session_id}' receipt.json
```

* Confidential model: `result` is `verified`, `required` is `true`, and `session_id` is present. The
  upstream enclave was verified and the channel bound before your prompt was forwarded.
* Routed model: `result` is `failed`, `required` is `false`, and there is no `session_id`. The upstream was
  not attested.

## What a passing verification proves

* The gateway is a specific reviewed workload in a genuine TEE (steps 1, 4).
* The response you received is exactly the response the gateway signed (step 5).
* The receipt is signed by a key bound to that workload (step 6).
* For a confidential model, the model ran on a verified, channel-bound upstream (step 7).

## Related

<CardGroup cols={2}>
  <Card title="Attestation report" icon="microchip" href="/confidential-ai/attestation-report" />

  <Card title="Receipts" icon="receipt" href="/confidential-ai/receipts" />

  <Card title="GET /v1/aci/attestation" icon="book" href="/api-reference/attestation" />

  <Card title="GET /v1/aci/receipts/{id}" icon="book" href="/api-reference/receipts" />
</CardGroup>
