{"ok":true,"meta":{"generatedAt":"2026-06-30T13:23:31.361Z"},"data":{"version":"tzv3-vip-club-handoff-v1","endpoint":"/api/club/handoff-policy","command":"npm run club:handoff","script":"scripts/tzv3-club-handoff.mjs","configured":true,"contractReady":true,"productionReady":false,"safety":{"mode":"read-only","writes":false,"network":false,"postsVerificationRequests":false,"createsTickets":false,"printsSecrets":false,"printsWebhookUrl":false,"storesWorkflowCredentials":false,"note":"Reports the external VIP verification receiver contract, expected headers, payload fields, and validation order. It never POSTs /api/club/verify and never prints webhook URL/token values."},"environment":{"required":[{"name":"VIP_CLUB_WEBHOOK_URL","configured":false,"placeholder":false},{"name":"VIP_CLUB_WEBHOOK_TOKEN","configured":false,"placeholder":false}],"relatedPublic":[{"name":"NEXT_PUBLIC_SITE_URL","configured":true,"placeholder":false}],"ownerSuppliedOutsideArtescEnv":[{"name":"VIP verification operator workflow","storage":"Telegram bot, Make/Zapier/n8n flow, or internal queue owned by the operator","reason":"Receives signed verification tickets and routes them to a human approval process."},{"name":"Operator approval procedure","storage":"Operations runbook outside this repo","reason":"Defines who may approve VIP/Private access and how approvals are recorded."}]},"receiver":{"mode":"receiver-url-required","targetEnvName":"VIP_CLUB_WEBHOOK_URL","secretEnvName":"VIP_CLUB_WEBHOOK_TOKEN","timeoutMs":5000,"expectedMethod":"POST","expectedContentType":"application/json","expectedHeaders":{"authorization":"Bearer <VIP_CLUB_WEBHOOK_TOKEN>","event":"x-artesc-event = vip_club.verification_requested","timestamp":"x-artesc-timestamp = ISO timestamp matching generatedAt","idempotency":"x-idempotency-key = ticketId","signature":"x-artesc-signature = sha256=<hmac>"},"signature":{"algorithm":"HMAC-SHA256","canonicalString":"<x-artesc-timestamp>.<raw request body>","verificationRule":"Compute HMAC-SHA256 over `${x-artesc-timestamp}.${rawBody}` with VIP_CLUB_WEBHOOK_TOKEN and compare to x-artesc-signature after removing the sha256= prefix.","replayGuard":"Reject duplicate x-idempotency-key values and stale x-artesc-timestamp values."}},"payloadContract":{"schemaVersion":"tzv3-vip-club-request-v2","source":"artesc-club","requiredFields":["adultConfirmed","privacyAccepted","contact","contactChannel","ticketId","generatedAt","source","schemaVersion"],"optionalFields":["preferredProfile","comment"],"acceptanceRules":["adultConfirmed must be true.","privacyAccepted must be true.","contactChannel must be telegram or phone.","ticketId must be treated as idempotency key.","Do not approve VIP/Private access automatically; route to a human operator."],"samplePayload":{"adultConfirmed":true,"privacyAccepted":true,"contact":"@client","contactChannel":"telegram","preferredProfile":"sofia","comment":"Prefer evening verification","source":"artesc-club","schemaVersion":"tzv3-vip-club-request-v2","ticketId":"club-<uuid>","generatedAt":"2026-06-03T00:00:00.000Z"}},"validation":{"noWriteFirst":["npm run club:handoff","curl -s https://your-domain.example/api/club/handoff-policy","curl -s https://your-domain.example/api/club/policy","npm run club:audit"],"finalProofs":["Receiver rejects missing authorization.","Receiver rejects stale x-artesc-timestamp.","Receiver rejects invalid x-artesc-signature.","Receiver deduplicates repeated x-idempotency-key values.","A real /api/club/verify request creates exactly one external workflow ticket only after owner approval."],"cannotVerifyFromArtesc":["The external receiver's internal approval queue.","Human operator identity checks.","Receiver-side duplicate ticket storage.","Any paid subscription or crypto payment model before legal/payment approval."]},"sourceSite":{"name":"artescort.vip","publicUrlConfigured":true,"clubPage":"/club","verifyEndpoint":"/api/club/verify"},"summary":{"requiredEnvironmentCount":2,"missingRequiredEnvironmentCount":2,"contractFailureCount":0,"expectedHeaderCount":5,"requiredPayloadFieldCount":8},"productionBoundary":["Run club:handoff before club:audit so the external receiver contract is reviewed without creating VIP verification tickets.","Set VIP_CLUB_WEBHOOK_URL and VIP_CLUB_WEBHOOK_TOKEN only in the deployment secret manager, not in the repository.","Do not enable subscriptions or payments until legal/payment approval is complete.","Do not POST /api/club/verify during no-write audits; that endpoint creates real workflow tickets when configured."],"contractFailures":[],"productionBlockers":["VIP_CLUB_WEBHOOK_URL is missing or placeholder","VIP_CLUB_WEBHOOK_TOKEN is missing or placeholder"]}}