{
  "app": {
    "name": "Mokabla",
    "url": "https://www.mokabla.com",
    "description": "Real interview questions from companies in Egypt, organised by company. Access is sold per company for 30 days."
  },
  "page": {
    "kind": "question",
    "title": "Question · idempotent-topup-api",
    "humanPath": "/en/c/orange/idempotent-topup-api",
    "humanOnly": false
  },
  "identity": {
    "class": "declared",
    "agent": "ClaudeBot",
    "operator": "Anthropic",
    "verified": false,
    "reason": "The user agent is ClaudeBot (Anthropic), which identifies itself as an AI agent.",
    "signals": [
      "Known agent user agent"
    ],
    "claimable": false
  },
  "state": {
    "question": {
      "slug": "idempotent-topup-api",
      "title": "Idempotent Top-Up API",
      "difficulty": "medium",
      "tags": [
        "coding",
        "oop-design",
        "technical",
        "backend"
      ],
      "is_free": true,
      "locked": false,
      "frequency": 0.75,
      "last_reported_at": "2026-06-14T22:54:45.272524Z",
      "url": "https://www.mokabla.com/en/c/orange/idempotent-topup-api",
      "agent": {
        "page": "https://www.mokabla.com/agent/en/c/orange/idempotent-topup-api",
        "question": "https://www.mokabla.com/agent/_call/get_question?company=orange&question=idempotent-topup-api"
      },
      "company": {
        "slug": "orange",
        "name_en": "Orange Egypt / Orange Business"
      },
      "body_md": "## Problem\nWe expose a Spring Boot endpoint `POST /topups` that adds credit to a subscriber's balance. Mobile clients retry on timeouts, so the same top-up sometimes arrives two or three times and the customer gets charged once but credited twice. Design the endpoint so that retries are safe, then implement the core service method in memory: `topUp(idempotencyKey, msisdn, amount)` returns the resulting balance and must produce exactly one credit per key, even under concurrent calls.\n\nIn the Java version I expect to hear about `@Transactional`, a unique constraint on the idempotency key, and what happens when two threads hit the method at once.\n\n## Examples\n**Example 1**\n`topUp(\"k1\", \"0100000001\", 50)` → balance 50; `topUp(\"k1\", \"0100000001\", 50)` again → still 50 (replayed response, no second credit); `topUp(\"k2\", \"0100000001\", 20)` → 70.\n\n**Example 2**\n`topUp(\"k9\", \"0100000002\", 30)` succeeds; `topUp(\"k9\", \"0100000002\", 99)`, same key, different payload → reject with a conflict error rather than silently returning the old result.\n\n## Constraints\n- Keys are client-generated UUIDs, valid for 24 hours\n- Two concurrent requests with the same key must not both credit\n- Balance is an integer number of piasters, never negative\n\n## What they look for\nStore-then-act ordering (insert the key first, credit second, inside one transaction), a DB unique constraint as the real guard, payload hash comparison for the conflict case, and knowing that `synchronized` does not help across two pods.",
      "follow_ups_md": "- Where would you cache the replayed response and for how long?\n- How does this interact with the payment gateway's own retries?\n- Which HTTP status for a replay, and which for a conflict?"
    },
    "paid": false,
    "access": "Question bodies are paid content: a person buys 30 days of access per company (200 EGP or 200 points) in the human app. Agents get titles, tags and difficulty; bodies only for free questions."
  },
  "actions": [
    {
      "name": "get_question",
      "description": "One question with its body. Bodies are paid content unless the question is free.",
      "permission": "allow",
      "sideEffect": "read",
      "input": {
        "company": "string",
        "question": "string"
      },
      "href": "https://www.mokabla.com/agent/_call/get_question?company=orange&question=idempotent-topup-api",
      "ready": true,
      "missing": [],
      "humanPath": "https://www.mokabla.com/en/pricing"
    },
    {
      "name": "list_questions",
      "description": "The questions reported at a company: titles, tags, difficulty, whether each is free or paid.",
      "permission": "allow",
      "sideEffect": "read",
      "input": {
        "company": "string",
        "page": "number?"
      },
      "href": "https://www.mokabla.com/agent/_call/list_questions?company=orange",
      "ready": true,
      "missing": []
    },
    {
      "name": "buy_access",
      "description": "Buy 30 days of access to a company.",
      "permission": "block",
      "reason": "This action is for people only",
      "ruleId": "R1",
      "sideEffect": "payment",
      "input": {
        "company": "string"
      },
      "href": "https://www.mokabla.com/agent/_call/buy_access?company=orange",
      "ready": true,
      "missing": [],
      "humanPath": "https://www.mokabla.com/en/pricing"
    },
    {
      "name": "post_comment",
      "description": "Comment on a question.",
      "permission": "block",
      "reason": "This action is for people only",
      "ruleId": "R1",
      "sideEffect": "write",
      "input": {
        "question": "string",
        "text": "string"
      },
      "href": "https://www.mokabla.com/agent/_call/post_comment?question=idempotent-topup-api",
      "ready": false,
      "missing": [
        "text"
      ],
      "humanPath": "https://www.mokabla.com/en/companies"
    }
  ],
  "navigate": [
    {
      "label": "This question, as data (free questions only)",
      "href": "https://www.mokabla.com/agent/_call/get_question?company=orange&question=idempotent-topup-api"
    },
    {
      "label": "All questions at this company",
      "href": "https://www.mokabla.com/agent/_call/list_questions?company=orange"
    },
    {
      "label": "The company page",
      "href": "https://www.mokabla.com/agent/en/c/orange"
    },
    {
      "label": "Idempotent Top-Up API · page",
      "href": "https://www.mokabla.com/agent/en/c/orange/idempotent-topup-api"
    }
  ],
  "notices": [
    {
      "severity": "info",
      "message": "This classification is final for the session: it came from a strong signal, not a guess. The human pages are not served to agents."
    },
    {
      "severity": "info",
      "message": "Unverified agents are read-only. Signed requests (Web Bot Auth) are the path to write access."
    }
  ],
  "meta": {
    "requestId": "ag_81db0c043fe3",
    "policyVersion": "mokabla-2026-11-03",
    "generatedAt": "2026-11-03T17:41:31.541Z",
    "jsonUrl": "https://www.mokabla.com/agent/en/c/orange/idempotent-topup-api?format=json",
    "manifestUrl": "https://www.mokabla.com/.well-known/agentgate.json",
    "humanUrl": "https://www.mokabla.com/en/c/orange/idempotent-topup-api",
    "humanClaimUrl": "https://www.mokabla.com/agent/_claim/human?to=%2Fen%2Fc%2Forange%2Fidempotent-topup-api"
  }
}