TUTORIAL
Gate a deploy on a receipt
In this tutorial you make a production deploy require an ACCEPTED Decision Receipt. You start with nothing, get an API key, define and dry-run the policy you will enforce, assemble a claim from artifacts your pipeline already has, and end with a shell gate that fails the deploy unless the verdict clears. Every endpoint here is live and public.
Work through the steps in order. Each one is a real request you can run against https://decrec.summitcognitive.ai. By the end you will have a deploy step that proceeds only when the decision is admissible, and a signed receipt saved as proof.
1. Get a key and export it
Every write endpoint needs an API key. Request one with POST /v1/signup — new signups start on the free tier (100 requests/hour). If the email already has a key, the same key is returned.
REQUEST
curl -s https://decrec.summitcognitive.ai/v1/signup \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}' | jq -r '.api_key'
Export the returned key so the later steps can read it. In CI, inject it from your secret store instead of exporting it inline.
SHELL
export DECREC_API_KEY="sk_decrec_<your-key>"
export API="https://decrec.summitcognitive.ai"
2. Define the production policy and dry-run it
A gate is only as good as the policy behind it. For a production deploy you want a strict bar, so override the defaults with a policyConfig: at least three sources, three distinct source types, an average confidence of 0.8 or higher, provenance on every source, a human sign-off, and a bounded risk scope.
| Field | Value | Why |
|---|---|---|
minSources | 3 | More than one signal must agree. |
minSourceTypes | 3 | Diversity of evidence, not three of the same kind. |
minConfidence | 0.8 | A high average bar for production. |
requireProvenance | true | Every source must carry chain-of-custody. |
requireHumanApproval | true | A human_approval source must be present. |
maxRiskScope | 3 | Cap how broad the change may be. |
Before you enforce anything, prove the policy out with POST /v1/simulate. It returns the same verdict shape as /v1/evaluate but does not persist a receipt, so you can see the verdict before it gates a real deploy.
DRY-RUN THE POLICY
curl -s "$API/v1/simulate" \
-H "Content-Type: application/json" \
-H "X-API-Key: $DECREC_API_KEY" \
-d '{
"claim_id": "dryrun-prod-001",
"entity": "acme-corp/widget-api",
"claim": "Dry-run: production deploy policy",
"sources": [
{ "id": "s1", "type": "ci", "uri": "https://example/ci", "confidence": 0.92, "content": "build green", "provenance": {"captured_at": "2026-06-22T10:00:00Z", "collector": "ci"} },
{ "id": "s2", "type": "test_result", "uri": "https://example/tests", "confidence": 0.90, "content": "tests passing", "provenance": {"captured_at": "2026-06-22T10:01:00Z", "collector": "ci"} },
{ "id": "s3", "type": "human_approval","uri": "https://example/signoff","confidence": 1.0, "content": "release signed", "provenance": {"captured_at": "2026-06-22T10:05:00Z", "collector": "release-mgr"} }
],
"policyConfig": {
"minSources": 3, "minSourceTypes": 3, "minConfidence": 0.8,
"requireProvenance": true, "requireHumanApproval": true, "maxRiskScope": 3
}
}' | jq '.policy'
Read the rules array in the response to see which checks pass and which would fail. Tune the thresholds here, against simulate, until the verdict matches your intent. Nothing is recorded yet.
3. Assemble the claim at deploy time
At the moment you are about to deploy, build the claim from artifacts you already have. The action object describes what is about to happen; the sources array carries the evidence. Use action_type deployment and set environment to production.
Map each artifact to a source type: ci for the build, test_result for the test job, code_review for the approval, policy_check for your scanner, and a human_approval source for the sign-off your policy now requires. That is five sources across five types — comfortably above the bar.
BUILD AND SUBMIT THE CLAIM
#!/usr/bin/env bash
set -euo pipefail
COMMIT="${CI_COMMIT_SHA:-abc1234}"
BRANCH="${CI_COMMIT_BRANCH:-main}"
curl -s "$API/v1/evaluate" \
-H "Content-Type: application/json" \
-H "X-API-Key: $DECREC_API_KEY" \
-d @- <<JSON > receipt-response.json
{
"claim_id": "deploy-${COMMIT}",
"entity": "acme-corp/widget-api",
"claim": "Deploy ${COMMIT} to production",
"action": {
"action_type": "deployment",
"target_system": "kubernetes",
"environment": "production",
"commit": "${COMMIT}",
"branch": "${BRANCH}",
"agent": "claude-code",
"human_operator": "release-mgr"
},
"sources": [
{ "id": "evd_ci_${COMMIT}", "type": "ci", "uri": "https://ci/run/1", "confidence": 0.92, "content": "Build green", "provenance": {"captured_at": "2026-06-22T10:00:00Z", "collector": "github-actions", "chain_of_custody": ["github", "decrec-client"]} },
{ "id": "evd_test_${COMMIT}", "type": "test_result", "uri": "https://ci/run/1", "confidence": 0.90, "content": "212 tests passing, 0 failures", "provenance": {"captured_at": "2026-06-22T10:01:00Z", "collector": "github-actions", "chain_of_custody": ["github", "decrec-client"]} },
{ "id": "evd_review_${COMMIT}", "type": "code_review", "uri": "https://github/pr/42", "confidence": 0.88, "content": "Approved, no blocking comments", "provenance": {"captured_at": "2026-06-22T10:02:00Z", "collector": "github-webhook", "chain_of_custody": ["github", "decrec-client"]} },
{ "id": "evd_policy_${COMMIT}", "type": "policy_check", "uri": "https://ci/run/1", "confidence": 0.95, "content": "Security scan clean", "provenance": {"captured_at": "2026-06-22T10:03:00Z", "collector": "scanner", "chain_of_custody": ["scanner", "decrec-client"]} },
{ "id": "evd_signoff_${COMMIT}","type": "human_approval","uri": "https://approvals/9", "confidence": 1.0, "content": "Release signed off by on-call lead", "provenance": {"captured_at": "2026-06-22T10:05:00Z", "collector": "release-mgr", "chain_of_custody": ["release-mgr", "decrec-client"]} }
],
"policyConfig": {
"minSources": 3, "minSourceTypes": 3, "minConfidence": 0.8,
"requireProvenance": true, "requireHumanApproval": true, "maxRiskScope": 3
}
}
JSON
Pass real evidence, not placeholders. The decision is only as trustworthy as the sources behind it — a confidence of 1.0 on a source that was never checked produces an admissible-looking receipt that means nothing. Capture what actually happened.
4. Gate the deploy on the result
The response carries two fields that together decide whether you ship. Proceed only when both clear: the policy verdict at .policy.verdict is ALLOWED and the receipt's admissibility at .receipt.admissibility.status is ACCEPTED. Halt on BLOCKED; route to a human on ESCALATED.
- ALLOWED + ACCEPTED — evidence cleared the policy and the receipt is admissible. Deploy.
- BLOCKED — a policy check failed. Stop the deploy.
- ESCALATED — the decision needs a human. Pause and route for review rather than auto-shipping.
Read both fields with jq and exit non-zero to fail the pipeline. A non-zero exit halts the step on every CI system.
GATE THE DEPLOY
VERDICT=$(jq -r '.policy.verdict' receipt-response.json)
ADMIT=$(jq -r '.receipt.admissibility.status' receipt-response.json)
if [ "$VERDICT" = "ALLOWED" ] && [ "$ADMIT" = "ACCEPTED" ]; then
echo "Admissible — deploying ${COMMIT} to production."
else
case "$VERDICT" in
ESCALATED) echo "Escalated — pausing for human review."; ;;
BLOCKED) echo "Blocked — refusing to deploy."; ;;
*) echo "Not admissible (verdict=$VERDICT admissibility=$ADMIT)."; ;;
esac
exit 1
fi
# ... your real deploy command runs only past this point ...
If you prefer a manual-approval path for ESCALATED instead of a hard failure, route to your platform's pause-for-approval feature in that branch — only the builds the verdict flags as needing a human will wait.
5. Store the receipt as a deploy artifact
An admissible verdict is only half the value. The response also includes a signed receipt — an Ed25519-attested record of the evidence, the policy result, and the replay result. Save it the way you save any deploy output.
SAVE THE RECEIPT
jq '.receipt' receipt-response.json > receipt-${COMMIT}.json
# upload receipt-${COMMIT}.json alongside your deploy artifacts
The receipt is independently verifiable later. Anyone — an auditor, a customer, your future self — can confirm it is genuine and unaltered without trusting your pipeline, by submitting it to POST /v1/verify or checking the Ed25519 signature offline against the server's published public key. See Verifying receipts for how that independent check works.
You now have a production deploy that runs only when the decision is admissible, with a signed receipt to prove it. To wire this into a specific provider — GitHub Actions, GitLab CI, Jenkins, Buildkite — see CI/CD integration. To understand exactly what each verdict and admissibility status means, see Policy verdicts.