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

> Learn how to verify a Confidential AI response with the gateway attestation report and signed receipt.

# Verify a Response

## What the receipt proves

Every Confidential AI response includes a signed receipt id in the `x-receipt-id` header. The receipt is an ordered transparency event log. It records request and response hashes, the selected route, upstream verification status, and the signature that binds the record to the attested gateway keyset.

For a confidential response, the receipt's `upstream.verified` event shows `result: verified`, `required: true`, and a `session_id`. That session records the verified upstream security context and channel binding.

## Prerequisites

```bash theme={"system"}
export API_KEY="<API_KEY>"
export BASE="https://inference.phala.com"
```

You need `curl`, `jq`, and a SHA-256 tool. On Linux use `sha256sum`; on macOS use `shasum -a 256`.

## 1. Fetch a fresh gateway attestation

```bash theme={"system"}
export NONCE="$(openssl rand -hex 16)"

curl -s "$BASE/v1/aci/attestation?nonce=$NONCE" \
  -H "Authorization: Bearer $API_KEY" \
  -o report.json
```

Verify the report as described in [Verify Attestation](/phala-cloud/confidential-ai/verify/verify-attestation). The receipt checks below assume you trust the attested keyset from this report.

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

```bash theme={"system"}
curl -s -D headers.txt "$BASE/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"phala/qwen3.5-27b",
       "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"
```

Keep `response.json`; the receipt commits to the exact response bytes.

## 3. Fetch the signed receipt

```bash theme={"system"}
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. Match the receipt to the attested gateway

```bash theme={"system"}
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"
```

If these values do not match, the receipt is not bound to the attestation report you verified.

## 5. Check the response hash

The `response.returned.wire_hash` event must match the bytes you received.

```bash theme={"system"}
# Linux:
RESP_HASH="sha256:$(sha256sum response.json | awk '{print $1}')"

# macOS alternative:
# RESP_HASH="sha256:$(shasum -a 256 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"
test "$RESP_HASH" = "$RECEIPT_RESP_HASH" && echo "response hash matches"
```

The receipt also contains `request.received.body_hash`. In production, hash the exact request body bytes you sent and compare them to that event.

## 6. Verify the receipt signature

The receipt signature covers the canonical receipt bytes. Verify it under one of the `receipt_signing_keys` entries from `attestation.workload_keyset`.

```bash theme={"system"}
# Conceptual:
# verifier check-receipt --attestation report.json --receipt receipt.json
```

A receipt signed by a key outside the attested keyset is not bound to the verified gateway and must fail verification.

## 7. Confirm the upstream was confidential

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

Interpretation:

* Confidential response: `result` is `verified`, `required` is `true`, and `session_id` is present.
* Routed response: `result` is `failed`, `required` is `false`, and no `session_id` is present. The gateway was attested, but the upstream provider was not.

To inspect the immutable upstream security context:

```bash theme={"system"}
SESSION_ID="$(jq -r '.event_log[] | select(.type=="upstream.verified") | .session_id' receipt.json)"

curl -s "$BASE/v1/aci/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $API_KEY" | \
  jq '{session_id, provider, endpoint, channel_binding, claims}'
```

## Legacy signature endpoint

Older clients may call `GET /v1/signature/{id}`. It returns the same receipt inside a compatibility envelope:

```bash theme={"system"}
curl -s "$BASE/v1/signature/$RECEIPT_ID" \
  -H "Authorization: Bearer $API_KEY"
```

New clients should use `GET /v1/aci/receipts/{id}` directly.

## What a passing verification proves

* The gateway is a specific reviewed workload in a genuine TEE.
* The receipt is signed by a key in the attested gateway keyset.
* The response you received is exactly the response the gateway signed.
* For a confidential model response, the upstream provider was verified and channel-bound before forwarding.
