{
  "info": {
    "name": "Sim Swap v1 - CIBA",
    "description": "Sim Swap v1 (SEP/CAMARA) - CIBA grant variant.\n\nClient authentication: PRIVATE_KEY_JWT only (RS256-signed client_assertion) - never client_secret.\n\nbase_url defaults to Germany staging (https://stg.api.telekom.com). Change only that one variable to target production or another country (see the base_url variable description).\n\nCIBA requires the subscriber to approve the authentication request out-of-band (e.g. on their device) between request 1 and request 2 completing successfully.\n\nCurrently listed for: 🇩🇪 Germany, 🇬🇷 Greece, 🇵🇱 Poland, 🇦🇹 Austria. (Source: this app's live product-catalog grant-type configuration, staging environment - see the /documentation/postman-collections page for the current matrix.)\n\nIMPORTANT: only one version of this API family can be ordered onto a single TMF Application - if your client_id/private_key were provisioned for Sim Swap v2 instead of this one (e.g. you ordered Sim Swap v1 but not v2, or vice versa), authentication will fail here with a 401 UNAUTHENTICATED/InvalidClaim error even though your credentials are otherwise valid and correctly entered. You need a client_id/private_key from an Application that specifically ordered THIS version to use this collection.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "1) BC-Authorize (start CIBA flow)",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (!pm.collectionVariables.get('client_id')) {",
              "    throw new Error('Set the client_id collection variable before running this request.');",
              "}",
              "const pk = pm.collectionVariables.get('private_key');",
              "if (!pk || pk.indexOf('PASTE-YOUR-PKCS8-PRIVATE-KEY-HERE') !== -1) {",
              "    throw new Error('Set the private_key collection variable (PKCS8 PEM) before running this request - placeholder still present.');",
              "}",
              "",
              "function b64urlFromBytes(bytes) {\n    let bin = '';\n    for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);\n    let b64 = btoa(bin);\n    return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction b64urlFromString(str) {\n    const utf8 = unescape(encodeURIComponent(str));\n    return b64urlFromBytes(Uint8ArrayFromBinaryString(utf8));\n}\n\nfunction Uint8ArrayFromBinaryString(bin) {\n    const arr = new Uint8Array(bin.length);\n    for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);\n    return arr;\n}\n\nfunction pemToDerBytes(pem) {\n    const b64 = pem\n        .replace(/-----BEGIN [^-]+-----/, '')\n        .replace(/-----END [^-]+-----/, '')\n        .replace(/\\s+/g, '');\n    const bin = atob(b64);\n    return Uint8ArrayFromBinaryString(bin);\n}\n\nfunction readDerTlv(bytes, offset) {\n    const tag = bytes[offset];\n    let lenByte = bytes[offset + 1];\n    let len, lenBytesUsed;\n    if ((lenByte & 0x80) === 0) {\n        len = lenByte;\n        lenBytesUsed = 1;\n    } else {\n        const numLenBytes = lenByte & 0x7f;\n        len = 0;\n        for (let i = 0; i < numLenBytes; i++) {\n            len = (len * 256) + bytes[offset + 2 + i];\n        }\n        lenBytesUsed = 1 + numLenBytes;\n    }\n    const contentStart = offset + 1 + lenBytesUsed;\n    return { tag, len, contentStart, nextOffset: contentStart + len };\n}\n\nfunction derToBigInt(bytes, start, len) {\n    let hex = '';\n    for (let i = 0; i < len; i++) {\n        const b = bytes[start + i];\n        hex += (b < 16 ? '0' : '') + b.toString(16);\n    }\n    if (hex === '') return BigInt(0);\n    return BigInt('0x' + hex);\n}\n\nfunction extractRsaPrivateKeyParams(pem) {\n    const bytes = pemToDerBytes(pem);\n    let tlv = readDerTlv(bytes, 0);\n    let cursor = tlv.contentStart;\n    let versionPeek = readDerTlv(bytes, cursor);\n    let second = readDerTlv(bytes, versionPeek.nextOffset);\n    let rsaKeyStart;\n    if (second.tag === 0x02) {\n        rsaKeyStart = cursor;\n    } else {\n        let versionTlv = readDerTlv(bytes, cursor);\n        cursor = versionTlv.nextOffset;\n        let algTlv = readDerTlv(bytes, cursor);\n        cursor = algTlv.nextOffset;\n        let octetTlv = readDerTlv(bytes, cursor);\n        let inner = readDerTlv(bytes, octetTlv.contentStart);\n        rsaKeyStart = inner.contentStart;\n    }\n    let p = rsaKeyStart;\n    let versionField = readDerTlv(bytes, p);\n    p = versionField.nextOffset;\n    let nField = readDerTlv(bytes, p);\n    const n = derToBigInt(bytes, nField.contentStart, nField.len);\n    p = nField.nextOffset;\n    let eField = readDerTlv(bytes, p);\n    p = eField.nextOffset;\n    let dField = readDerTlv(bytes, p);\n    const d = derToBigInt(bytes, dField.contentStart, dField.len);\n    const modulusByteLength = Math.ceil(n.toString(2).length / 8);\n    return { n, d, modulusByteLength };\n}\n\nfunction modPow(base, exp, mod) {\n    let result = BigInt(1);\n    base = base % mod;\n    while (exp > BigInt(0)) {\n        if (exp % BigInt(2) === BigInt(1)) {\n            result = (result * base) % mod;\n        }\n        exp = exp / BigInt(2);\n        base = (base * base) % mod;\n    }\n    return result;\n}\n\nconst SHA256_DIGEST_INFO_PREFIX_HEX =\n    '3031300d060960864801650304020105000420';\n\nfunction hexToBytes(hex) {\n    const arr = new Uint8Array(hex.length / 2);\n    for (let i = 0; i < arr.length; i++) {\n        arr[i] = parseInt(hex.substr(i * 2, 2), 16);\n    }\n    return arr;\n}\n\nfunction bytesToHex(bytes) {\n    let hex = '';\n    for (let i = 0; i < bytes.length; i++) {\n        hex += (bytes[i] < 16 ? '0' : '') + bytes[i].toString(16);\n    }\n    return hex;\n}\n\nfunction emsaPkcs1v15Encode(digestHex, k) {\n    const digestInfoHex = SHA256_DIGEST_INFO_PREFIX_HEX + digestHex;\n    const digestInfo = hexToBytes(digestInfoHex);\n    const tLen = digestInfo.length;\n    if (k < tLen + 11) {\n        throw new Error('RSA modulus too short for SHA-256 PKCS1v1.5 padding');\n    }\n    const psLen = k - tLen - 3;\n    const em = new Uint8Array(k);\n    em[0] = 0x00;\n    em[1] = 0x01;\n    for (let i = 0; i < psLen; i++) em[2 + i] = 0xff;\n    em[2 + psLen] = 0x00;\n    em.set(digestInfo, 3 + psLen);\n    return em;\n}\n\nfunction bytesToBigInt(bytes) {\n    return BigInt('0x' + (bytesToHex(bytes) || '0'));\n}\n\nfunction bigIntToBytes(bi, length) {\n    let hex = bi.toString(16);\n    if (hex.length % 2 !== 0) hex = '0' + hex;\n    let bytes = hexToBytes(hex);\n    if (bytes.length < length) {\n        const padded = new Uint8Array(length);\n        padded.set(bytes, length - bytes.length);\n        bytes = padded;\n    }\n    return bytes;\n}\n\nfunction rs256Sign(signingInput, privateKeyPem) {\n    const { n, d, modulusByteLength } = extractRsaPrivateKeyParams(privateKeyPem);\n    const digestHex = CryptoJS.SHA256(signingInput).toString(CryptoJS.enc.Hex);\n    const em = emsaPkcs1v15Encode(digestHex, modulusByteLength);\n    const m = bytesToBigInt(em);\n    const s = modPow(m, d, n);\n    const sigBytes = bigIntToBytes(s, modulusByteLength);\n    return b64urlFromBytes(sigBytes);\n}\n\nfunction buildSignedJwt(headerObj, payloadObj, privateKeyPem) {\n    const headerB64 = b64urlFromString(JSON.stringify(headerObj));\n    const payloadB64 = b64urlFromString(JSON.stringify(payloadObj));\n    const signingInput = headerB64 + '.' + payloadB64;\n    const sig = rs256Sign(signingInput, privateKeyPem);\n    return signingInput + '.' + sig;\n}",
              "",
              "const clientId = pm.collectionVariables.get('client_id');",
              "const privateKey = pm.collectionVariables.get('private_key');",
              "const kid = pm.collectionVariables.get('kid');",
              "const tokenEndpoint = (pm.collectionVariables.get('base_url') + '/token');",
              "const now = Math.floor(Date.now() / 1000);",
              "const header = { alg: 'RS256', typ: 'JWT' };",
              "if (kid) { header.kid = kid; }",
              "const payload = {",
              "    iss: clientId,",
              "    sub: clientId,",
              "    aud: tokenEndpoint,",
              "    iat: now,",
              "    exp: now + 300,",
              "    jti: pm.variables.replaceIn('{{$guid}}')",
              "};",
              "const clientAssertion = buildSignedJwt(header, payload, privateKey);",
              "pm.collectionVariables.set('client_assertion', clientAssertion);",
              "pm.collectionVariables.set('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const json = pm.response.json();",
              "if (json.auth_req_id) {",
              "    pm.collectionVariables.set('auth_req_id', json.auth_req_id);",
              "    pm.collectionVariables.set('interval', String(json.interval || 5));",
              "    pm.collectionVariables.set('expires_in', String(json.expires_in || 120));",
              "    pm.collectionVariables.set('poll_attempts', '0');",
              "    console.log('auth_req_id captured, interval=' + (json.interval || 5) + 's. Approve the request on the subscriber device, then run the next request (it will auto-poll).');",
              "} else {",
              "    console.error('No auth_req_id in response:', JSON.stringify(json));",
              "}",
              "pm.test('bc-authorize response has auth_req_id', function () {",
              "    pm.expect(json.auth_req_id, JSON.stringify(json)).to.be.a('string');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/x-www-form-urlencoded",
            "type": "text"
          }
        ],
        "body": {
          "mode": "urlencoded",
          "urlencoded": [
            {
              "key": "scope",
              "value": "{{scope}}",
              "type": "text"
            },
            {
              "key": "login_hint",
              "value": "tel:{{phone_number}}",
              "type": "text"
            },
            {
              "key": "client_id",
              "value": "{{client_id}}",
              "type": "text"
            },
            {
              "key": "client_assertion_type",
              "value": "{{client_assertion_type}}",
              "type": "text"
            },
            {
              "key": "client_assertion",
              "value": "{{client_assertion}}",
              "type": "text"
            }
          ]
        },
        "url": {
          "raw": "{{base_url}}/bc-authorize",
          "host": [
            "{{base_url}}/bc-authorize"
          ]
        },
        "description": "Starts a CIBA (Client Initiated Backchannel Authentication) flow for the subscriber tel:{{phone_number}}. Captures auth_req_id, interval and expires_in into collection variables for the next (polling) request."
      },
      "response": []
    },
    {
      "name": "2) Poll Token (CIBA, auto-retries)",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (!pm.collectionVariables.get('client_id')) {",
              "    throw new Error('Set the client_id collection variable before running this request.');",
              "}",
              "const pk = pm.collectionVariables.get('private_key');",
              "if (!pk || pk.indexOf('PASTE-YOUR-PKCS8-PRIVATE-KEY-HERE') !== -1) {",
              "    throw new Error('Set the private_key collection variable (PKCS8 PEM) before running this request - placeholder still present.');",
              "}",
              "",
              "function b64urlFromBytes(bytes) {\n    let bin = '';\n    for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);\n    let b64 = btoa(bin);\n    return b64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction b64urlFromString(str) {\n    const utf8 = unescape(encodeURIComponent(str));\n    return b64urlFromBytes(Uint8ArrayFromBinaryString(utf8));\n}\n\nfunction Uint8ArrayFromBinaryString(bin) {\n    const arr = new Uint8Array(bin.length);\n    for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);\n    return arr;\n}\n\nfunction pemToDerBytes(pem) {\n    const b64 = pem\n        .replace(/-----BEGIN [^-]+-----/, '')\n        .replace(/-----END [^-]+-----/, '')\n        .replace(/\\s+/g, '');\n    const bin = atob(b64);\n    return Uint8ArrayFromBinaryString(bin);\n}\n\nfunction readDerTlv(bytes, offset) {\n    const tag = bytes[offset];\n    let lenByte = bytes[offset + 1];\n    let len, lenBytesUsed;\n    if ((lenByte & 0x80) === 0) {\n        len = lenByte;\n        lenBytesUsed = 1;\n    } else {\n        const numLenBytes = lenByte & 0x7f;\n        len = 0;\n        for (let i = 0; i < numLenBytes; i++) {\n            len = (len * 256) + bytes[offset + 2 + i];\n        }\n        lenBytesUsed = 1 + numLenBytes;\n    }\n    const contentStart = offset + 1 + lenBytesUsed;\n    return { tag, len, contentStart, nextOffset: contentStart + len };\n}\n\nfunction derToBigInt(bytes, start, len) {\n    let hex = '';\n    for (let i = 0; i < len; i++) {\n        const b = bytes[start + i];\n        hex += (b < 16 ? '0' : '') + b.toString(16);\n    }\n    if (hex === '') return BigInt(0);\n    return BigInt('0x' + hex);\n}\n\nfunction extractRsaPrivateKeyParams(pem) {\n    const bytes = pemToDerBytes(pem);\n    let tlv = readDerTlv(bytes, 0);\n    let cursor = tlv.contentStart;\n    let versionPeek = readDerTlv(bytes, cursor);\n    let second = readDerTlv(bytes, versionPeek.nextOffset);\n    let rsaKeyStart;\n    if (second.tag === 0x02) {\n        rsaKeyStart = cursor;\n    } else {\n        let versionTlv = readDerTlv(bytes, cursor);\n        cursor = versionTlv.nextOffset;\n        let algTlv = readDerTlv(bytes, cursor);\n        cursor = algTlv.nextOffset;\n        let octetTlv = readDerTlv(bytes, cursor);\n        let inner = readDerTlv(bytes, octetTlv.contentStart);\n        rsaKeyStart = inner.contentStart;\n    }\n    let p = rsaKeyStart;\n    let versionField = readDerTlv(bytes, p);\n    p = versionField.nextOffset;\n    let nField = readDerTlv(bytes, p);\n    const n = derToBigInt(bytes, nField.contentStart, nField.len);\n    p = nField.nextOffset;\n    let eField = readDerTlv(bytes, p);\n    p = eField.nextOffset;\n    let dField = readDerTlv(bytes, p);\n    const d = derToBigInt(bytes, dField.contentStart, dField.len);\n    const modulusByteLength = Math.ceil(n.toString(2).length / 8);\n    return { n, d, modulusByteLength };\n}\n\nfunction modPow(base, exp, mod) {\n    let result = BigInt(1);\n    base = base % mod;\n    while (exp > BigInt(0)) {\n        if (exp % BigInt(2) === BigInt(1)) {\n            result = (result * base) % mod;\n        }\n        exp = exp / BigInt(2);\n        base = (base * base) % mod;\n    }\n    return result;\n}\n\nconst SHA256_DIGEST_INFO_PREFIX_HEX =\n    '3031300d060960864801650304020105000420';\n\nfunction hexToBytes(hex) {\n    const arr = new Uint8Array(hex.length / 2);\n    for (let i = 0; i < arr.length; i++) {\n        arr[i] = parseInt(hex.substr(i * 2, 2), 16);\n    }\n    return arr;\n}\n\nfunction bytesToHex(bytes) {\n    let hex = '';\n    for (let i = 0; i < bytes.length; i++) {\n        hex += (bytes[i] < 16 ? '0' : '') + bytes[i].toString(16);\n    }\n    return hex;\n}\n\nfunction emsaPkcs1v15Encode(digestHex, k) {\n    const digestInfoHex = SHA256_DIGEST_INFO_PREFIX_HEX + digestHex;\n    const digestInfo = hexToBytes(digestInfoHex);\n    const tLen = digestInfo.length;\n    if (k < tLen + 11) {\n        throw new Error('RSA modulus too short for SHA-256 PKCS1v1.5 padding');\n    }\n    const psLen = k - tLen - 3;\n    const em = new Uint8Array(k);\n    em[0] = 0x00;\n    em[1] = 0x01;\n    for (let i = 0; i < psLen; i++) em[2 + i] = 0xff;\n    em[2 + psLen] = 0x00;\n    em.set(digestInfo, 3 + psLen);\n    return em;\n}\n\nfunction bytesToBigInt(bytes) {\n    return BigInt('0x' + (bytesToHex(bytes) || '0'));\n}\n\nfunction bigIntToBytes(bi, length) {\n    let hex = bi.toString(16);\n    if (hex.length % 2 !== 0) hex = '0' + hex;\n    let bytes = hexToBytes(hex);\n    if (bytes.length < length) {\n        const padded = new Uint8Array(length);\n        padded.set(bytes, length - bytes.length);\n        bytes = padded;\n    }\n    return bytes;\n}\n\nfunction rs256Sign(signingInput, privateKeyPem) {\n    const { n, d, modulusByteLength } = extractRsaPrivateKeyParams(privateKeyPem);\n    const digestHex = CryptoJS.SHA256(signingInput).toString(CryptoJS.enc.Hex);\n    const em = emsaPkcs1v15Encode(digestHex, modulusByteLength);\n    const m = bytesToBigInt(em);\n    const s = modPow(m, d, n);\n    const sigBytes = bigIntToBytes(s, modulusByteLength);\n    return b64urlFromBytes(sigBytes);\n}\n\nfunction buildSignedJwt(headerObj, payloadObj, privateKeyPem) {\n    const headerB64 = b64urlFromString(JSON.stringify(headerObj));\n    const payloadB64 = b64urlFromString(JSON.stringify(payloadObj));\n    const signingInput = headerB64 + '.' + payloadB64;\n    const sig = rs256Sign(signingInput, privateKeyPem);\n    return signingInput + '.' + sig;\n}",
              "",
              "const clientId = pm.collectionVariables.get('client_id');",
              "const privateKey = pm.collectionVariables.get('private_key');",
              "const kid = pm.collectionVariables.get('kid');",
              "const tokenEndpoint = (pm.collectionVariables.get('base_url') + '/token');",
              "const now = Math.floor(Date.now() / 1000);",
              "const header = { alg: 'RS256', typ: 'JWT' };",
              "if (kid) { header.kid = kid; }",
              "const payload = {",
              "    iss: clientId,",
              "    sub: clientId,",
              "    aud: tokenEndpoint,",
              "    iat: now,",
              "    exp: now + 300,",
              "    jti: pm.variables.replaceIn('{{$guid}}')",
              "};",
              "const clientAssertion = buildSignedJwt(header, payload, privateKey);",
              "pm.collectionVariables.set('client_assertion', clientAssertion);",
              "pm.collectionVariables.set('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const MAX_ATTEMPTS = 24; // ~2 minutes at the default 5s interval",
              "let json = {};",
              "try { json = pm.response.json(); } catch (e) { json = {}; }",
              "const attempts = parseInt(pm.collectionVariables.get('poll_attempts') || '0', 10);",
              "const intervalSeconds = parseInt(pm.collectionVariables.get('interval') || '5', 10);",
              "",
              "if (json.access_token) {",
              "    pm.collectionVariables.set('access_token', json.access_token);",
              "    console.log('access_token captured after ' + attempts + ' poll(s). Advancing to Sim Swap check.');",
              "    postman.setNextRequest('3) Sim Swap v1 - Check');",
              "} else if (json.error === 'authorization_pending' || json.error === 'slow_down') {",
              "    const nextAttempts = attempts + 1;",
              "    pm.collectionVariables.set('poll_attempts', String(nextAttempts));",
              "    if (json.error === 'slow_down') {",
              "        pm.collectionVariables.set('interval', String(intervalSeconds + 5));",
              "    }",
              "    if (nextAttempts >= MAX_ATTEMPTS) {",
              "        console.error('CIBA polling gave up after ' + nextAttempts + ' attempts.');",
              "        postman.setNextRequest(null);",
              "    } else {",
              "        console.log('CIBA pending (' + json.error + '), attempt ' + nextAttempts + '/' + MAX_ATTEMPTS + '. Waiting ' + intervalSeconds + 's before retrying.');",
              "        setTimeout(function () {",
              "            postman.setNextRequest('2) Poll Token (CIBA, auto-retries)');",
              "        }, intervalSeconds * 1000);",
              "    }",
              "} else {",
              "    console.error('CIBA polling stopped due to error:', JSON.stringify(json));",
              "    postman.setNextRequest(null);",
              "}"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/x-www-form-urlencoded",
            "type": "text"
          }
        ],
        "body": {
          "mode": "urlencoded",
          "urlencoded": [
            {
              "key": "grant_type",
              "value": "urn:openid:params:grant-type:ciba",
              "type": "text"
            },
            {
              "key": "auth_req_id",
              "value": "{{auth_req_id}}",
              "type": "text"
            },
            {
              "key": "client_id",
              "value": "{{client_id}}",
              "type": "text"
            },
            {
              "key": "client_assertion_type",
              "value": "{{client_assertion_type}}",
              "type": "text"
            },
            {
              "key": "client_assertion",
              "value": "{{client_assertion}}",
              "type": "text"
            }
          ]
        },
        "url": {
          "raw": "{{base_url}}/token",
          "host": [
            "{{base_url}}/token"
          ]
        },
        "description": "Polls the token endpoint for the outcome of the CIBA request. A fresh client_assertion is signed on every poll. Auto-retries on authorization_pending/slow_down (respecting the server's interval), capped at ~24 attempts (~2 minutes), then auto-advances to the Sim Swap check request once access_token is captured. Run request 1 first."
      },
      "response": []
    },
    {
      "name": "3) Sim Swap v1 - Check",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{access_token}}",
            "type": "text"
          },
          {
            "key": "Content-Type",
            "value": "application/json",
            "type": "text"
          },
          {
            "key": "x-correlator",
            "value": "{{$guid}}",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n    \"maxAge\": {{max_age}}\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{base_url}}/sim-swap/v1/check",
          "host": [
            "{{base_url}}"
          ],
          "path": [
            "sim-swap",
            "v1",
            "check"
          ]
        },
        "description": "CAMARA Sim Swap v1 check. maxAge=240 hours matches this app's SEP_APIs.razor default. The device is identified entirely via the access token (sub claim) for this grant type - including a phoneNumber/device field in the body causes a real UNNECESSARY_IDENTIFIER (422) error, so it is omitted here."
      },
      "response": []
    },
    {
      "name": "4) Sim Swap v1 - Retrieve Date",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{access_token}}",
            "type": "text"
          },
          {
            "key": "Content-Type",
            "value": "application/json",
            "type": "text"
          },
          {
            "key": "x-correlator",
            "value": "{{$guid}}",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{base_url}}/sim-swap/v1/retrieve-date",
          "host": [
            "{{base_url}}"
          ],
          "path": [
            "sim-swap",
            "v1",
            "retrieve-date"
          ]
        },
        "description": "CAMARA Sim Swap v1 retrieve-date. No maxAge field here - matches SEPAPIs.cs RetrieveSimSwapDateEndpoint, which only ever sends phoneNumber (never maxAge) in the body."
      },
      "response": []
    },
    {
      "name": "5) Sim Swap v1 - Health",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{access_token}}",
            "type": "text"
          },
          {
            "key": "x-correlator",
            "value": "{{$guid}}",
            "type": "text"
          }
        ],
        "url": {
          "raw": "{{base_url}}/sim-swap/v1/health",
          "host": [
            "{{base_url}}"
          ],
          "path": [
            "sim-swap",
            "v1",
            "health"
          ]
        },
        "description": "Health check GET for Sim Swap v1 (no request body, matches SEPAPIs.cs ExecuteHealthGet)."
      },
      "response": []
    }
  ],
  "variable": [
    {
      "key": "base_url",
      "value": "https://stg.api.telekom.com",
      "type": "string",
      "description": "Germany staging by default. Change ONLY this variable to switch environment/country: production Germany = https://api.telekom.com; Austria staging = https://at.stg.api.telekom.com, Austria prod = https://at.api.telekom.com; Poland and Greece staging/prod hosts follow the same at.*/pl.*/gr.* pattern - see this app's /documentation/endpoints page for the full current list. Every request and script in this collection builds the full endpoint path directly from base_url (e.g. {{base_url}}/token) rather than through a separate derived variable, because Postman does not resolve nested variable references (a variable whose value itself contains {{...}}) when read inside pre-request/test scripts via pm.collectionVariables.get() - only base_url itself needs to be correct. "
    },
    {
      "key": "client_id",
      "value": "",
      "type": "string",
      "description": "REQUIRED. Your registered OAuth client_id for the SimSwapV1 credential profile. Never commit a real value here."
    },
    {
      "key": "private_key",
      "value": "-----BEGIN PRIVATE KEY-----\nPASTE-YOUR-PKCS8-PRIVATE-KEY-HERE\n-----END PRIVATE KEY-----",
      "type": "string",
      "description": "REQUIRED. PKCS8 PEM RSA private key used to sign the private_key_jwt client_assertion (and, for the JWT Bearer variant, the subscriber assertion). Replace the placeholder text between the BEGIN/END markers with your real PKCS8 PEM key. Never commit a real private key."
    },
    {
      "key": "kid",
      "value": "",
      "type": "string",
      "description": "Optional key ID matching a key in your JWKS - leave blank if your JWKS has only one key."
    },
    {
      "key": "phone_number",
      "value": "+491702049821",
      "type": "string",
      "description": "Standard test MSISDN for this API from this app's live DE staging standard configuration (SepStandardApiConfigurations table, per-API/country/environment) - not a generic sample number."
    },
    {
      "key": "max_age",
      "value": "240",
      "type": "string",
      "description": "Sim Swap maxAge in hours - 240 is the default already used by this app's SEP_APIs.razor."
    },
    {
      "key": "client_assertion_type",
      "value": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
      "type": "string",
      "description": "Fixed value for private_key_jwt client authentication - auto-set by the pre-request script too."
    },
    {
      "key": "client_assertion",
      "value": "",
      "type": "string",
      "description": "Auto-populated by the pre-request script on each token request. Do not edit."
    },
    {
      "key": "access_token",
      "value": "",
      "type": "string",
      "description": "Auto-populated by the token request's test script. Do not edit."
    },
    {
      "key": "scope",
      "value": "openid sim-swap:check sim-swap:retrieve-date dpv:FraudPreventionAndDetection",
      "type": "string",
      "description": "openid sim-swap:check sim-swap:retrieve-date dpv:FraudPreventionAndDetection - 'openid' is prefixed because SEPAPIs.cs's UsesOpenIdScope returns true for GrantType == CIBA."
    },
    {
      "key": "auth_req_id",
      "value": "",
      "type": "string",
      "description": "Auto-populated by the bc-authorize request's test script. Do not edit."
    },
    {
      "key": "interval",
      "value": "5",
      "type": "string",
      "description": "Auto-populated polling interval (seconds) from the bc-authorize response. Do not edit."
    },
    {
      "key": "expires_in",
      "value": "",
      "type": "string",
      "description": "Auto-populated auth_req_id validity window (seconds) from the bc-authorize response. Do not edit."
    },
    {
      "key": "poll_attempts",
      "value": "0",
      "type": "string",
      "description": "Internal poll counter used by the polling request's test script. Do not edit."
    }
  ]
}
