Skip to content

Callback Format

ScamShield AI sends intelligence callbacks to report extracted evidence and scam analysis. Callbacks are sent on every turn from turn 1 onward, using overwrite semantics to ensure the latest intelligence is always available.

Callback URL

POST https://hackathon.guvi.in/api/updateHoneyPotFinalResult

The callback URL is hardcoded in GuviCallbackService. The endpoint uses "update" (overwrite) semantics -- sending a callback for the same session replaces the previous one.

Callback Authentication

Header Value
Content-Type application/json
x-api-key The SCAMSHIELD_API_KEY value

The same API key used for incoming requests is sent with outgoing callbacks.

Trigger Conditions

Callbacks are sent on every turn starting from turn 1 (CALLBACK_MIN_TURN = 1). This ensures:

  • Intelligence is submitted even for 1-turn evaluations
  • Each callback contains the latest cumulative evidence
  • The endpoint's overwrite semantics make repeated sends safe

Per-Turn Callback (Primary)

Every incoming message triggers:

  1. Process the message (classify, generate response, extract evidence)
  2. Send callback with all accumulated evidence from the session
  3. Return the honeypot response

Delayed Callback (Secondary, via Cloud Tasks)

A separate mechanism schedules a delayed callback after 10 seconds of inactivity:

  1. Each incoming message schedules (or reschedules) a Cloud Tasks task
  2. If no new message arrives within 10 seconds, the task fires
  3. The task calls send_delayed_callback, which sends the final intelligence report
  4. The task is authenticated via OIDC token (see OIDC Verification)

This mechanism ensures a final callback is sent even if the per-turn callback failed on the last turn.

Callback Payload

{
  "sessionId": "session-abc-123",
  "status": "success",
  "scamDetected": true,
  "scamType": "KYC_BANKING",
  "confidenceLevel": 0.92,
  "totalMessagesExchanged": 5,
  "engagementDurationSeconds": 450.5,
  "engagementMetrics": {
    "engagementDurationSeconds": 450.5,
    "totalMessagesExchanged": 5
  },
  "extractedIntelligence": {
    "bankAccounts": [],
    "upiIds": ["sbikyc@oksbi"],
    "phishingLinks": ["http://sbi-kyc.xyz/verify"],
    "phoneNumbers": ["9876543210"],
    "emailAddresses": ["fake.sbi@gmail.com"],
    "suspiciousKeywords": ["KYC", "OTP", "account blocked", "urgent", "fee"],
    "ifscCodes": [],
    "cryptoWallets": [],
    "aadhaarNumbers": [],
    "panNumbers": [],
    "amounts": ["500"],
    "caseIds": [],
    "policyNumbers": [],
    "orderNumbers": []
  },
  "agentNotes": "Scam Type: KYC/Banking verification scam attempting to steal credentials\nConfidence: 92%\nPersona Used: sharma_uncle\nEngagement Duration: 5 messages\n\nEvidence Extracted:\nUPI IDs: sbikyc@oksbi\nPhishing URLs: http://sbi-kyc.xyz/verify\nPhone numbers: 9876543210\nEmails: fake.sbi@gmail.com\nKeywords: KYC, OTP, account blocked, urgent, fee\n\nStrategy: Engaged scammer using sharma_uncle persona with delay tactics\nand trust-building to maximize time wasted and intelligence extraction."
}

Payload Field Reference

Field Type Description
sessionId string Session identifier (echoed from the original request).
status "success" Always "success" for callbacks.
scamDetected boolean Whether a scam was detected. Same logic as the per-turn response.
scamType string \| null Classified scam type (e.g., "KYC_BANKING", "DIGITAL_ARREST").
confidenceLevel float \| null Detection confidence (0.0 to 1.0).
totalMessagesExchanged int Total messages exchanged in the session.
engagementDurationSeconds float \| null Seconds since the session started.
engagementMetrics object Nested engagement data (mirrors top-level fields).
extractedIntelligence object All 14 evidence fields (cumulative across all turns). See extractedIntelligence.
agentNotes string Human-readable summary of the analysis, scam type, evidence, and strategy.

Cloud Tasks Scheduling

The delayed callback uses Google Cloud Tasks to schedule execution after a period of inactivity.

How It Works

Turn 1: Message arrives
  → Process message, send per-turn callback
  → Schedule Cloud Tasks task (fires in 10s)

Turn 2: Message arrives (within 10s)
  → Cancel previous task
  → Process message, send per-turn callback
  → Schedule new Cloud Tasks task (fires in 10s)

... no more messages ...

10 seconds later:
  → Cloud Tasks fires send_delayed_callback
  → Final intelligence report sent with all accumulated evidence

Task Configuration

Parameter Value
Queue callback-queue
Region asia-south1
Delay 10 seconds after the last message
Auth OIDC token (service account)
Target https://asia-south1-your-gcp-project-id.cloudfunctions.net/send_delayed_callback

Task Payload

{
  "sessionId": "session-abc-123"
}

The send_delayed_callback function reads the full session state from Firestore and constructs the callback payload.

OIDC Token Verification

The delayed callback endpoint (send_delayed_callback) verifies that requests originate from Cloud Tasks, not arbitrary callers.

How It Works

  1. Cloud Tasks adds an Authorization: Bearer <token> header to the request
  2. The token is an OIDC JWT signed by Google, with the service account email as the email claim
  3. verify_cloud_tasks_token() validates the token using Google's public keys
  4. It checks that the email claim matches your-gcp-project-id@appspot.gserviceaccount.com

Verification Flow

# In send_delayed_callback:
from utils.oidc import verify_cloud_tasks_token

ok, err_msg = verify_cloud_tasks_token(request)
if not ok:
    return Response({"error": err_msg}, status=403)

Dev Mode

In local development (where K_SERVICE environment variable is not set), OIDC verification is skipped:

if not os.environ.get("K_SERVICE"):
    logger.debug("Skipping OIDC verification (local dev)")
    return True, ""

Retry and Circuit Breaker

The callback service includes resilience patterns:

Retry

  • Max retries: 1 attempt per turn (kept low because callbacks are sent every turn)
  • Backoff: Exponential (2^attempt seconds)
  • Failed attempts are effectively retried on the next turn with fresher data

Circuit Breaker

  • Failure threshold: 3 consecutive failures
  • Reset timeout: 60 seconds
  • When the circuit is open, callbacks are skipped (logged as error) until the timeout expires
  • This prevents cascading failures if the callback endpoint is down
Normal → 3 failures → Circuit OPEN (60s) → Half-Open → Test request
  ↓                                                         ↓
Success                                               Success → CLOSED
                                                      Failure → OPEN (60s)