Stratify
Internal ops

Partner Runbook

docs/closed-beta/partner-runbook.md

Source updated 03. Aug. 2026

Closed beta — partner integration test (unaided, v2.1)

Status (2026-05-22): v2.0 runbook (mirror orders + suitability delegation) is parked — see docs/api/phase-c-endpoints.md. Phase A: use docs/api/quickstart.md: list mandates → fetch signals → GET …/order-intents → subscribe webhook → verify webhook v2 (HMAC) → audit export with chainVerified: true. Mapping: docs/api/partner-order-mapping.md.

Goal: one neobroker engineer completes this runbook without Stratify support and produces artifacts proving read/write access, suitability delegation, and audit visibility.

Replace placeholders:

PlaceholderExample
BASEhttps://your-preview.vercel.app or local http://localhost:3000
STKRaw key from tmp/closed-beta/manifest.json (stk_sbx_…)
PILOTpilotId from the same manifest

0. Preconditions

  1. Stratify ops ran pnpm seed:closed-beta against the sandbox database and sent you the manifest (prefix-only over Slack is OK; full key via vault).
  2. Your egress IP is allowed if Stratify enabled IP allowlisting (default off in sandbox).
  3. STRATIFY_SANDBOX_MODE=1 on the deployment under test (paused pilots visible, IBKR mocked).

1. Smoke — authentication

curl -sS "$BASE/api/v1/pilots" \
  -H "Authorization: Bearer $STK" \
  -H "Accept: application/json" | jq .

Expect 200 and at least one pilot with status: "live".

Artifact: save response JSON as artifacts/01-pilots.json.

2. Strategy contract

curl -sS "$BASE/api/v1/pilots/$PILOT/strategy" \
  -H "Authorization: Bearer $STK" | jq .

Confirm definition matches your UI expectations (asset universe, risk bands).

Artifact: artifacts/02-strategy.json.

3. Mirror order — suitability path

Pick a test user email you control (no production PII).

RUN_ID="$(date +%s)-$RANDOM"
EMAIL="[email protected]"

curl -sS -X POST "$BASE/api/v1/mirror-orders" \
  -H "Authorization: Bearer $STK" \
  -H "Content-Type: application/json" \
  -d @- <<EOF | jq .
{
  "partnerUserId": "partner_runbook_$RUN_ID",
  "pilotId": "$PILOT",
  "side": "BUY",
  "instrumentSymbol": "VWCE",
  "notionalEur": 100,
  "idempotencyKey": "runbook-$RUN_ID",
  "userProfile": {
    "email": "$EMAIL",
    "suitabilityAnswers": {
      "k.derivatives_familiarity": "basic",
      "k.copy_trading_understanding": true,
      "f.annual_net_income_eur": 80000,
      "f.liquid_assets_eur": 120000,
      "f.intended_investment_eur": 10000,
      "f.can_afford_total_loss": true,
      "o.horizon_years": 10,
      "o.risk_tolerance": "medium"
    }
  }
}
EOF
  • 201 / 200: order accepted — note propagatedOrderId / leg ids if returned.
  • 409 suitability_failed: answers failed MiFID-II gate — expected if you sent borderline data; adjust answers per Stratify suitability spec (do not invent wording for end users).

Artifact: artifacts/03-mirror-order-response.json.

Re-send the same idempotencyKey once — response must be identical (idempotency proof).

4. Inbound execution webhook (optional sandbox hook)

If Stratify gave you a signing secret for inbound POST /api/v1/webhooks/execution-status, replay the OpenAPI example payload with valid HMAC. Otherwise skip — outbound delivery is covered next.

5. Outbound webhook — signature verification

Configure webhookUrl on the partner record to a request inspector (e.g. webhook.site) or your staging ingress.

Trigger an execution status update (mirror order above + sandbox propagation). Stratify POSTs JSON with header:

X-Stratify-Signature: sha256=<hex>

Verify:

expected = HMAC_SHA256(webhookSecret, rawBody)

Constant-time compare with sha256= prefix.

Artifact: one captured raw request + your verifier script output.

6. Audit read scope

After a successful mirror order, fetch audit entries for the same partnerUserId you sent in step 3 (the path param is your id, not an internal UUID). Reuse the exact partnerUserId string from the JSON body in step 3 (same shell session as $RUN_ID, or copy-paste from artifacts/03).

curl -sS "$BASE/api/v1/audit-log/partner_runbook_$RUN_ID" \
  -H "Authorization: Bearer $STK" | jq .

If you used a different partnerUserId, substitute it literally. Expect entries for b2c_user, user_order_leg, and propagated_order subjects tied to that user.

Artifact: artifacts/06-audit-log.json.

7. Done criteria (partner self-check)

  • [ ] 0106 artifacts attached to internal ticket
  • [ ] Idempotency re-play confirmed
  • [ ] Webhook signature verified OR documented skip with reason
  • [ ] No Stratify engineer contacted during steps 1–6

Escalation only for: HTTP 5xx &gt;15 minutes, unexpected 401, or schema mismatch vs openapi/stratify-api.yaml.