{
  "info": {
    "name": "TMF Onboarding (App Owner + Application + Product Order) - Client Secret",
    "description": "Full TMF931 onboarding flow: create an Application Owner, create an Application under that owner, then order the SEP CAMARA API product for that application. Uses CLIENT_SECRET client authentication for the onboarding API token, matching this app's TMF931Controller.cs exactly.\n\nRun the requests in order, top to bottom - each captures the id it needs into a collection variable for the next request (owner_id, app_id, order_id).\n\nSwitching environment: change ONLY the host variable. Defaults to the staging onboarding host (https://api-dc71.lotusflare.com). Production onboarding host is https://sep.api.telekom.com. The realm variable controls which country/operator you onboard against (dtmace = Germany, dtmaceaustria = Austria, dtmacepoland = Poland, dtmacegreece = Greece) - see this app's /documentation/endpoints page for the full reference.\n\nNote: this creates a real Application Owner, Application and Product Order against the TMF platform - there is no sandbox/dry-run mode. Use test/sample values you're comfortable with, and a product_offering_id you were actually approved for.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "1) Get Access Token (Client Credentials + Client Secret)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const json = pm.response.json();",
              "if (json.access_token) {",
              "    pm.collectionVariables.set('access_token', json.access_token);",
              "    console.log('access_token captured.');",
              "} else {",
              "    console.error('No access_token in response:', JSON.stringify(json));",
              "}",
              "pm.test('Token response has access_token', function () {",
              "    pm.expect(json.access_token, 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": "grant_type",
              "value": "client_credentials",
              "type": "text"
            },
            {
              "key": "client_id",
              "value": "{{cp_client_id}}",
              "type": "text"
            },
            {
              "key": "client_secret",
              "value": "{{cp_client_secret}}",
              "type": "text"
            }
          ]
        },
        "url": {
          "raw": "{{host}}/realms/{{realm}}/protocol/openid-connect/token",
          "host": [
            "{{host}}/realms/{{realm}}/protocol/openid-connect/token"
          ]
        },
        "description": "Obtains an access token for the TMF931 onboarding/ordering API using CLIENT_SECRET client authentication (grant_type=client_credentials) - this is the exact method this app's TMF931Controller.cs GetAccessToken always uses. Captures access_token into a collection variable for the requests that follow."
      },
      "response": []
    },
    {
      "name": "2) Create Application Owner",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const json = pm.response.json();",
              "if (json.id) {",
              "    pm.collectionVariables.set('owner_id', json.id);",
              "    console.log('Application Owner id captured: ' + json.id);",
              "} else {",
              "    console.error('No id in Application Owner response:', JSON.stringify(json));",
              "}",
              "pm.test('Application Owner response has id', function () {",
              "    pm.expect(json.id, JSON.stringify(json)).to.be.a('string');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{access_token}}",
            "type": "text"
          },
          {
            "key": "Content-Type",
            "value": "application/json",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n    \"@type\": \"ApplicationOwner\",\n    \"@baseType\": \"PartyRole\",\n    \"name\": \"{{owner_name}}\",\n    \"description\": \"Postman test Application Owner, created via the TMF931 onboarding API.\",\n    \"engagedParty\": {\n        \"@type\": \"ApplicationOwnerOrganization\",\n        \"@baseType\": \"Organization\",\n        \"name\": \"{{owner_name}} Org\",\n        \"tradingName\": \"Postman Test Org\",\n        \"isLegalEntity\": true,\n        \"organizationType\": \"dpv:ForProfitOrganisation\",\n        \"privacyPolicyURL\": \"https://example.com/privacy\",\n        \"taxNumber\": \"00.000.000/0000-00\",\n        \"organizationIdentification\": [\n            {\n                \"@type\": \"OrganizationIdentification\",\n                \"identificationType\": \"companyRegistration\",\n                \"identificationId\": \"00.000.000/0000-00\",\n                \"issuingAuthority\": \"Federal\"\n            }\n        ],\n        \"registeredGeographicAddress\": {\n            \"@type\": \"LightGeographicAddress\",\n            \"@baseType\": \"GeographicAddress\",\n            \"streetNr\": \"123\",\n            \"streetName\": \"Avenida Paulista\",\n            \"locality\": \"Paraíso\",\n            \"city\": \"São Paulo\",\n            \"stateOrProvince\": \"São Paulo\",\n            \"countryCode\": {\n                \"@type\": \"ISO31661Alpha2StandardIdentifier\",\n                \"@baseType\": \"StandardIdentifier\",\n                \"value\": \"BR\"\n            },\n            \"postcode\": \"01311-000\",\n            \"geographicSubAddress\": {\n                \"@type\": \"LightGeographicSubAddress\",\n                \"@baseType\": \"GeographicSubAddress\",\n                \"buildingName\": \"Fogo\",\n                \"levelNumber\": \"Planta 4\"\n            }\n        },\n        \"contactMedium\": [\n            {\n                \"@type\": \"EmailContactMedium\",\n                \"@baseType\": \"ContactMedium\",\n                \"id\": \"1\",\n                \"preferred\": true,\n                \"emailAddress\": \"integrationtest@example.de\",\n                \"contactType\": \"professional\"\n            }\n        ],\n        \"privacyManager\": {\n            \"@type\": \"ApplicationOwnerRelatedOrganization\",\n            \"name\": \"Privacy Office\",\n            \"organizationType\": \"department\",\n            \"contactMedium\": [\n                {\n                    \"@type\": \"EmailContactMedium\",\n                    \"id\": \"1\",\n                    \"preferred\": true,\n                    \"@baseType\": \"ContactMedium\",\n                    \"emailAddress\": \"integrationtest@example.de\"\n                }\n            ]\n        }\n    }\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{host}}/{{base_path}}/applicationOwner",
          "host": [
            "{{host}}/{{base_path}}/applicationOwner"
          ]
        },
        "description": "Creates a TMF ApplicationOwner (party role) - the organization/team that will own the SEP CAMARA application. Response id is captured into owner_id for the next requests. Field names and sample values match this app's TMF931Controller.cs CreateApplicationOwner method verbatim."
      },
      "response": []
    },
    {
      "name": "3) Create Application",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const json = pm.response.json();",
              "if (json.id) {",
              "    pm.collectionVariables.set('app_id', json.id);",
              "    console.log('Application id captured: ' + json.id);",
              "} else {",
              "    console.error('No id in Application response:', JSON.stringify(json));",
              "}",
              "pm.test('Application response has id', function () {",
              "    pm.expect(json.id, JSON.stringify(json)).to.be.a('string');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{access_token}}",
            "type": "text"
          },
          {
            "key": "Content-Type",
            "value": "application/json",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n    \"@type\": \"Application\",\n    \"name\": \"{{app_name}}\",\n    \"description\": \"Postman test Application, created via the TMF931 onboarding API.\",\n    \"category\": \"games\",\n    \"commercialName\": \"Postman Test App Commercial Name\",\n    \"applicationOwner\": {\n        \"id\": \"{{owner_id}}\",\n        \"@type\": \"PartyRoleRef\"\n    },\n    \"jwksUri\": \"{{jwks_uri}}\",\n    \"redirectUrl\": [\n        \"{{redirect_url}}\"\n    ],\n    \"digitalIdentity\": {\n        \"@type\": \"ApiDigitalIdentity\",\n        \"clientId\": \"{{requested_client_id}}\"\n    }\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{host}}/{{base_path}}/application",
          "host": [
            "{{host}}/{{base_path}}/application"
          ]
        },
        "description": "Creates a TMF Application under the Application Owner created in the previous request (owner_id). requested_client_id becomes the client_id your new SEP CAMARA application will use to obtain access tokens for service API calls. redirect_url/jwks_uri should point at your own infrastructure. Response id is captured into app_id for the next request. Field names match this app's TMF931Controller.cs CreateApplication method verbatim."
      },
      "response": []
    },
    {
      "name": "4) Create Product Order",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const json = pm.response.json();",
              "if (json.id) {",
              "    pm.collectionVariables.set('order_id', json.id);",
              "    console.log('Product Order id captured: ' + json.id);",
              "} else {",
              "    console.error('No id in Product Order response:', JSON.stringify(json));",
              "}",
              "pm.test('Product Order response has id', function () {",
              "    pm.expect(json.id, JSON.stringify(json)).to.be.a('string');",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{access_token}}",
            "type": "text"
          },
          {
            "key": "Content-Type",
            "value": "application/json",
            "type": "text"
          }
        ],
        "body": {
          "mode": "raw",
          "raw": "{\n    \"productOrderItem\": [\n        {\n            \"approvedProductOfferingTermOrCondition\": [\n                {\n                    \"productOfferingTermOrConditionSpecRef\": {\n                        \"id\": \"1\",\n                        \"name\": \"device_location_verification_terms\",\n                        \"version\": \"1.1\",\n                        \"@type\": \"ProductOfferingTermOrConditionSpecRef\"\n                    },\n                    \"name\": \"Device Location Term or Condition\",\n                    \"productOfferingTermOrConditionApproval\": {\n                        \"approvalDate\": \"{{$isoTimestamp}}\",\n                        \"authorization\": [\n                            {\n                                \"@type\": \"ApiAuthorization\",\n                                \"name\": \"Application Owner representative\",\n                                \"approver\": {\n                                    \"partyOrPartyRole\": {\n                                        \"@type\": \"PartyRoleRef\",\n                                        \"id\": \"{{owner_id}}\"\n                                    },\n                                    \"@type\": \"RelatedPartyRefOrPartyRoleRef\",\n                                    \"role\": \"applicationOwner\"\n                                }\n                            }\n                        ]\n                    },\n                    \"@type\": \"ProductOfferingTermOrCondition\",\n                    \"purposeReason\": \"legal entity\"\n                }\n            ],\n            \"productAction\": {\n                \"purpose\": \"{{purpose}}\",\n                \"@baseType\": \"ApiProductActionAdd\",\n                \"targetApplication\": {\n                    \"@type\": \"ApplicationRef\",\n                    \"id\": \"{{app_id}}\"\n                },\n                \"@type\": \"ApiProductActionAdd\"\n            },\n            \"@baseType\": \"ProductOrderItem\",\n            \"productOffering\": {\n                \"@type\": \"ProductOfferingRef\",\n                \"id\": \"{{product_offering_id}}\",\n                \"name\": \"{{product_offering_name}}\"\n            },\n            \"@type\": \"ApiProductOrderItemAdd\",\n            \"id\": \"orderItemId\"\n        }\n    ],\n    \"@baseType\": \"ProductOrder\",\n    \"@type\": \"ApiProductOrder\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "{{host}}/{{base_path}}/apiProductOrder",
          "host": [
            "{{host}}/{{base_path}}/apiProductOrder"
          ]
        },
        "description": "Orders the SEP CAMARA API product (product_offering_id, provided by the DT MACE team) for the Application created in the previous request (app_id), approved on behalf of the Application Owner (owner_id). approvalDate uses Postman's {{$isoTimestamp}} dynamic variable so it's always current. Response id is captured into order_id. Field names/shape match this app's TMF931Controller.cs OrderProduct method verbatim."
      },
      "response": []
    },
    {
      "name": "5) Get Product Order Status (optional)",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const json = pm.response.json();",
              "console.log('Order state: ' + json.state);",
              "pm.test('Order status request succeeded', function () {",
              "    pm.response.to.have.status(200);",
              "});"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{access_token}}",
            "type": "text"
          }
        ],
        "url": {
          "raw": "{{host}}/{{base_path}}/apiProductOrder/{{order_id}}",
          "host": [
            "{{host}}/{{base_path}}/apiProductOrder/{{order_id}}"
          ]
        },
        "description": "Optional: checks the status/state of the Product Order created in the previous request (order_id). Useful to confirm the order completed (e.g. state = 'completed') before trying to use the new application's credentials."
      },
      "response": []
    }
  ],
  "variable": [
    {
      "key": "host",
      "value": "https://api-dc71.lotusflare.com",
      "type": "string",
      "description": "TMF onboarding host. Default is the staging onboarding host used by this app's TMF931Controller.cs. Change ONLY this variable to switch to production: https://sep.api.telekom.com. The path (base_path) and realm are the same across environments; only the host differs. See this app's /documentation/endpoints page for the full onboarding endpoint reference."
    },
    {
      "key": "base_path",
      "value": "tmf-api/openGatewayOperateAPIOnboardingAndOrdering/v5",
      "type": "string",
      "description": "Fixed TMF931 API base path - do not change unless the onboarding API version changes."
    },
    {
      "key": "realm",
      "value": "dtmace",
      "type": "string",
      "description": "Keycloak realm (operator name) used for the token endpoint, and for the TMF onboarding channel partner credentials. Germany = dtmace. Other countries: Austria = dtmaceaustria, Poland = dtmacepoland, Greece = dtmacegreece. See this app's /documentation/endpoints page for the full per-country realm reference."
    },
    {
      "key": "token_endpoint_description_only",
      "value": "",
      "type": "string",
      "disabled": true,
      "description": "Not used directly - kept only so the token endpoint formula is documented: {{host}}/realms/{{realm}}/protocol/openid-connect/token."
    },
    {
      "key": "cp_client_id",
      "value": "",
      "type": "string",
      "description": "REQUIRED. Your Channel Partner client ID for the TMF931 onboarding API itself (this authenticates YOU as the channel partner calling the onboarding/ordering API - it is separate from requested_client_id below, which is the client ID your new SEP CAMARA application will use for service API calls)."
    },
    {
      "key": "cp_client_secret",
      "value": "",
      "type": "string",
      "description": "REQUIRED. Your Channel Partner client secret for the TMF931 onboarding API (issued alongside cp_client_id). Never share this outside your own systems."
    },
    {
      "key": "owner_name",
      "value": "Postman Test Owner",
      "type": "string",
      "description": "Sample Application Owner name. Change to your own organization/team name if you want a recognizable owner in the TMF platform."
    },
    {
      "key": "app_name",
      "value": "Postman Test App",
      "type": "string",
      "description": "Sample Application name for the new TMF Application resource."
    },
    {
      "key": "requested_client_id",
      "value": "",
      "type": "string",
      "description": "REQUIRED. The client_id you want your new SEP CAMARA application to use for service API calls (KYC Match, Sim Swap, etc.) - this becomes the digitalIdentity.clientId of the created Application."
    },
    {
      "key": "redirect_url",
      "value": "https://yourapp.com/redirect",
      "type": "string",
      "description": "Your application's OAuth redirect URI, used for Authorization Code / CIBA flows on the resulting SEP CAMARA application. Point this at your own infrastructure."
    },
    {
      "key": "jwks_uri",
      "value": "https://yourapp.com/.well-known/jwks.json",
      "type": "string",
      "description": "Your application's public JWKS endpoint (HTTPS), used if the resulting SEP CAMARA application authenticates with private_key_jwt. Point this at your own infrastructure - send the URI to the DT MACE team for whitelisting."
    },
    {
      "key": "product_offering_id",
      "value": "",
      "type": "string",
      "description": "REQUIRED. The Product Offering ID for the SEP CAMARA API you were approved for - provided by the DT MACE team during onboarding, not guessable."
    },
    {
      "key": "product_offering_name",
      "value": "offering-name",
      "type": "string",
      "description": "Sample product offering name (matches this app's TMF931Controller.cs default parameter value) - descriptive only, does not need to match a real catalog name."
    },
    {
      "key": "purpose",
      "value": "dpv:FraudPreventionAndDetection",
      "type": "string",
      "description": "GDPR/DPV purpose for the product order - dpv:FraudPreventionAndDetection is this app's TMF931Controller.cs default. Change to match the actual purpose of your use case if different."
    },
    {
      "key": "access_token",
      "value": "",
      "type": "string",
      "description": "Auto-populated by the token request. Do not edit manually."
    },
    {
      "key": "owner_id",
      "value": "",
      "type": "string",
      "description": "Auto-populated by the Create Application Owner request. Do not edit manually."
    },
    {
      "key": "app_id",
      "value": "",
      "type": "string",
      "description": "Auto-populated by the Create Application request. Do not edit manually."
    },
    {
      "key": "order_id",
      "value": "",
      "type": "string",
      "description": "Auto-populated by the Create Product Order request. Do not edit manually."
    }
  ]
}
