Getting Started with Oracle Radio APIs

Use the mobile OAuth configuration managed by Public Safety and Security to obtain an Identity Domain access token and call a supported Oracle Radio REST or WebSocket operation.

Use Console, CLI, or API in Step 1 to get the Public Safety and Security instance endpoints. For Radio operations, use the available Radio app, REST API, or WebSocket API tab. The supported mobile application handles OAuth sign-in, registration completion, and its connection automatically; Steps 4 through 8 explain the client implementation. Review the permissions for the chosen method.

Choose REST for individual requests, such as enabling a Radio user, registering a device, reading a profile, or saving account settings. Choose WebSocket for an ongoing, two-way connection that receives live channel events and carries push-to-talk audio or messages. A live client often uses both: REST prepares saved state, then WebSocket manages the current session. The operations aren't interchangeable; a saved REST subscription doesn't join a live connection. See the Overview's API comparison for connection and reconnect responsibilities.

This walkthrough explains requests made by supported Radio mobile clients. The cURL and PowerShell examples illustrate those requests; they do not provide a supported command-line login workflow. Command-line, custom-browser, and server authentication contracts are not currently supported. Do not create an OAuth application or change client settings managed by Public Safety and Security to use these examples. See supported authentication.

Before You Begin

This quick start applies to a supported Radio mobile application that uses the public OAuth client provisioned by Public Safety and Security. Use the application's Authorization Code flow with PKCE to obtain the access token used in this walkthrough.

You need an active Public Safety and Security instance or must create one, an enabled Radio user, the permissions and channel access required by the operation, and an administrator-created device registration for that user. Review authentication before you begin.

Step 1: Get the Active Public Safety and Security Instance Endpoints

Choose a method below to get instance details. Continue only when the lifecycle state is ACTIVE. The returned endpoints have these purposes:

  • serviceEndpoint is the complete API URL, including the trailing /api/. Assign this value directly to PSS_SERVICE_ENDPOINT, the environment variable used in the REST examples in this quick start.
    https://<unique-id>.pss.<region>.oci.oraclecloud.com/api/
  • uiEndpoint is the complete Radio user-interface URL, including the trailing /ui/. Open this URL to use Oracle Radio.
    https://<unique-id>.pss.<region>.oci.oraclecloud.com/ui/

Copy the values from the instance details. Use the returned hostname; don't construct it from the instance OCID or region, and don't add a port number.

Derive the WebSocket URL when you reach Step 8.

    1. In the OCI Console, open the Navigation menu, select Oracle Public Safety and Security, and then under Public Safety and Security, select Instances.
    2. Select the compartment, and then select the Public Safety and Security instance.
    3. Confirm that the lifecycle state is ACTIVE.
    4. Copy the API service endpoint and Radio app user interface endpoint.
      Use serviceEndpoint for API requests and uiEndpoint to open Oracle Radio.
  • Use an authenticated OCI CLI installation with Public Safety and Security support. See CLI setup.

    1. Run this command with your instance OCID:

      oci pss instance get --instance-id <instance-OCID>
    2. Confirm that the returned lifecycle-state is ACTIVE.

    3. Copy service-endpoint for API requests and ui-endpoint for Oracle Radio. For all returned fields, see instance details.

    For a complete list of flags and variable options for CLI commands, see the Command Line Reference.

    1. Call GetInstance with the instance OCID.

    2. Confirm that the returned lifecycleState is ACTIVE.

    3. Copy serviceEndpoint for API requests and uiEndpoint for Oracle Radio.

Step 2: Prepare the Oracle Radio User and Access

A Radio administrator enables access and assigns Radio groups to the intended Identity Domain user. Identity Domain accounts and groups are separate from Radio access and groups.

Both methods require radio.user.manage.

    1. Open the uiEndpoint from Step 1 and sign in as a Radio administrator.
      https://<unique-id>.pss.<region>.oci.oraclecloud.com/ui/
    2. Select Users, and use Search users to find the intended user.

    3. Select Enable if Radio access isn't already enabled.

    4. Select Manage. Under Groups, select the least-privilege Radio groups needed for the user's operations, and select Save groups.

    5. Verify the saved access and memberships, and any required channel access. See user management for details.

  • Use an administrator's already authenticated API client. If one isn't available, use the Radio app tab.

    1. List users to find the intended Identity Domain user ID.

    2. Get details to check the user's directory and Radio state.

    3. Enable access if Radio access isn't already enabled. Send this body to PUT /api/v1/management/users/<directory-user-id>/status:

      {"status":"ENABLED"}

      Retain the returned radio.radioUserId for the next request.

    4. Replace memberships with the complete desired set of Radio group IDs. Send the body to PUT /api/v1/management/users/<radio-user-id>/groups, using the Radio user ID, not the directory ID:

      {"groupIds":["<radio-group-id>"]}

      Include every existing membership to retain. The example assigns one group; an empty array removes all memberships.

    5. Get the user details again to verify access and memberships. Verify any required channel access.

Step 3: Create a Device Registration

Create a short-lived, one-time registration grant for the user enabled in Step 2. The registration supplies public client configuration and a grant, not an OAuth token or client secret. For repeated enrollment, see reusable registration.

Creating a grant requires radio.enrollment.manage. The Radio app's Devices page also requires radio.device.manage. The seeded Radio Administrators group includes these permissions.

    1. In Radio, select Devices, and then select Register device.

    2. Choose the user, and enter the display name and a future expiration.

    3. Leave Reusable QR code cleared, and select Create QR code.

    4. Deliver the QR code securely to the intended user. See device registration for details.

  • Use the supported authentication flow.

    1. Find an eligible user with listDeviceRegistrationUsers.
    2. Use the returned Radio user ID, a display name, and a future expiration in createDeviceRegistration.
    3. Retain the returned descriptor for the client flow, or give its qrValue securely to the intended user. See registration values.

    The administrator creates the grant; the intended user's token is used later to complete it. If this is the first mobile enrollment and the administrator has no authenticated API client, use the Radio app tab.

Step 4: Prepare the OAuth Authorization Request

The supported mobile app performs this flow during sign-in. For a client implementation, prepare a separate Authorization Code + PKCE transaction for each sign-in attempt.

  1. Read the Radio base URL, Identity Domain URL, public mobile client ID, and exact Radio authorization scope from the registration value created in Step 3.

  2. Retrieve the Identity Domain's discovery document. Use the Identity Domain URL from the registration value, not the Public Safety and Security serviceEndpoint:

    GET https://idcs-<unique-id>.identity.oraclecloud.com/.well-known/openid-configuration

    Retain authorization_endpoint, token_endpoint, issuer, and jwks_uri from the response. See OCI token validation for discovery and signing-key guidance.

  3. Generate a new PKCE verifier and its S256 challenge, a random state value, and a nonce. Retain the verifier, state, and nonce privately for this attempt. Send only the challenge, not the verifier, in the authorization request.

  4. Build an authorization URL using the discovered authorization_endpoint, public mobile client ID, and the supported callback com.oracle.pss.mobile:/oauth/callback. Request openid, offline_access, and the exact Radio scope from the registration value; don't reconstruct or normalize the scope.

    Replace the marked values in this sanitized example. URL encode each parameter value; the callback is already encoded. Join the lines into one URL:

    https://idcs-<unique-id>.identity.oraclecloud.com/oauth2/v1/authorize
    ?response_type=code
    &client_id=<public-mobile-client-id>
    &redirect_uri=com.oracle.pss.mobile%3A%2Foauth%2Fcallback
    &scope=openid%20offline_access%20<url-encoded-radio-scope>
    &state=<new-random-state>
    &nonce=<new-random-nonce>
    &code_challenge=<S256-code-challenge>
    &code_challenge_method=S256

    The installed application owns this callback; the registration value doesn't change it. The public mobile client doesn't send a client secret.

  5. Open the assembled URL in the system browser and have the intended user sign in and complete any required consent. The browser returns to the installed application's callback with a code and state, not an access token:

    HTTP/1.1 302 Found
    Location: com.oracle.pss.mobile:/oauth/callback?code=<authorization-code>&state=<original-state>
  6. Validate the callback target and state before proceeding to Step 5. If the state doesn't match or the callback contains error, stop the attempt and follow sign in help. Keep the callback URI and its code out of logs and support records.

For the Identity Domain protocol, see OCI Authorization Code.

Step 5: Request an OAuth Access Token

Exchange the code from Step 4 for the bearer access token used by Radio APIs. The supported mobile app does this automatically; these steps describe the client implementation.

Important

Don't copy mobile app credentials into a terminal, create another Identity Domain application, or add a client secret. Public Safety and Security provisions the public mobile client. Use the public-client PKCE instructions in OCI Authorization Code, not the confidential-client examples with Basic authentication.
  1. Accept the authorization code only after validating the callback target and state from Step 4.
    If the callback contains an error or the state doesn't match, stop that attempt and restart sign-in. Keep the original PKCE verifier and nonce for this same attempt.
  2. Send an HTTPS POST to the discovered token_endpoint with a form-encoded body containing these values.

    Use the following parameters in the form-encoded token request.

    ParameterValue
    grant_typeauthorization_code
    client_idThe public mobile client ID used in Step 4, supplied by the registration descriptor.
    redirect_uriThe same supported callback used in Step 4: com.oracle.pss.mobile:/oauth/callback.
    codeThe authorization code from the validated callback, not the registration grant or QR value.
    code_verifierThe original PKCE verifier whose S256 challenge was sent in Step 4. Don't send the challenge or generate a replacement verifier.

    This sanitized request shows the exchange. Substitute the discovered token URL and current transaction values. URL-encode each form value; the callback is already encoded. Join the body lines into one form body without line breaks. Don't send JSON, a client secret, or a Radio bearer token in this request.

    POST https://idcs-<unique-id>.identity.oraclecloud.com/oauth2/v1/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=authorization_code
    &client_id=<url-encoded-public-mobile-client-id>
    &redirect_uri=com.oracle.pss.mobile%3A%2Foauth%2Fcallback
    &code=<url-encoded-authorization-code>
    &code_verifier=<url-encoded-original-PKCE-verifier>
  3. Confirm HTTP 200 and read the token response securely.

    This illustrative response excerpt uses placeholders, not usable credentials:

    {
      "access_token": "<access-token>",
      "id_token": "<ID-token>",
      "token_type": "Bearer"
    }

    The complete response can contain additional fields, including expires_in and scope. Use the returned values; don't assume a fixed token lifetime. A rejected exchange doesn't produce a usable token. Follow exchange help instead of repeatedly submitting the same code.

  4. Validate the tokens before trusting the sign-in result.
    Use an OpenID Connect library to verify signatures against the discovered signing keys, the expected issuer, and expiry. For the ID token, also verify the client-ID audience and the original nonce. Verify that the access token is for the intended user and Radio resource scope. See OCI token validation. Use access_token, not id_token, for Radio requests.
  5. Protect the tokens in platform-protected storage and continue to device registration.
    If a refresh_token is issued, protect it too and follow the supported application's renewal flow. OCI's refresh-token instructions include a public-client example. Don't log tokens, authorization codes, PKCE verifiers, registration codes, or QR values.

The application has an Identity Domain bearer access token for the intended enabled Radio user. The token exchange doesn't register the device or grant additional Radio permissions.

Continue to Step 6 to complete registration, then use Step 7 to verify Radio API access. The supported mobile app performs these operations for the user.

Step 6: Complete Device Registration

Complete registration once for the installation, using the intended enabled user's session and one-time grant. The administrator's enrollment permission authorizes grant creation; it doesn't replace the intended user's authentication.

  • If this installation is already registered, don't scan or submit the consumed grant again.

    1. Open the supported mobile application and scan the administrator-issued QR code.

    2. Sign in as the intended enabled user identified by the registration. The application performs the OAuth exchange described in Steps 4 and 5.

    3. Allow the application to complete registration and retain its device ID. For a failed attempt, follow registration help.

    See device registration for the full workflow. Continue using the app; the remaining API steps explain the operations performed by a client.

  • Use completeDeviceRegistration for a new installation after the intended user completes Step 5.

    1. Read the HTTPS origin from the registration descriptor's radioBaseUrl. Prepare the one-time grant, the intended user's current access token, and the installation's opaque advertising ID.

    2. Send this request to that origin. Replace the marked values. The all-zero advertising ID shown is valid; supply the opaque advertising ID for your installation.

      POST /api/v1/radio/device-registrations/completions
      Authorization: Bearer <access-token>
      Content-Type: application/json
      {
        "code": "<one-time-registration-grant>",
        "advertisingId": "00000000-0000-0000-0000-000000000000"
      }
    3. Confirm HTTP 201 and read device.radioDeviceId from the response. The example ID below is illustrative; use the returned value.

      {
        "device": {
          "radioDeviceId": "a3b5c7d9e1f2406a8b0c2d4e6f8091a2"
        }
      }
    4. Store the returned Radio device ID as protected installation state for later device requests and the WebSocket upgrade. Don't repeat a successful completion request with the consumed grant.

    For the full response and request constraints, see registration completion. The registration grant and Radio device ID don't replace the bearer access token. For an expired, consumed, or revoked grant, follow registration help.

Step 7: Verify REST Access

Verify that the user's Radio groups grant radio.channel.list, which is required by the profile operation.

Run the read-only getRadioProfile operation to confirm that Radio accepts the access token and resolves it to the intended enabled Radio user. Choose a request tool below; these are REST examples, not OCI CLI commands.

Important

Use temporary protected values. Don't save an access token in a script, shell history, source file, or support record.
    1. In a POSIX-style shell, set PSS_SERVICE_ENDPOINT to the exact serviceEndpoint from Step 1, including the trailing /api/.

    2. Make the current access token available as RADIO_ACCESS_TOKEN through protected temporary input. Don't paste a literal token into a saved command or shell history.

    3. Request the profile and clear the temporary token variable:

      curl --request GET \
        --header "Authorization: Bearer ${RADIO_ACCESS_TOKEN}" \
        --header "Accept: application/json" \
        "${PSS_SERVICE_ENDPOINT}v1/radio/me"
      unset RADIO_ACCESS_TOKEN
    4. Follow response checks before continuing.

    1. In PowerShell, set $env:PSS_SERVICE_ENDPOINT to the exact serviceEndpoint from Step 1, including the trailing /api/.

    2. Make the current access token available as $env:RADIO_ACCESS_TOKEN through protected temporary input. Don't paste a literal token into a saved command or shell history.

    3. Request the profile and clear the temporary headers and token variable, including if the request fails:

      $headers = @{
        Authorization = "Bearer $env:RADIO_ACCESS_TOKEN"
        Accept = "application/json"
      }
      try {
        Invoke-RestMethod `
          -Method Get `
          -Uri "$($env:PSS_SERVICE_ENDPOINT)v1/radio/me" `
          -Headers $headers
      } finally {
        Remove-Variable headers
        Remove-Item Env:RADIO_ACCESS_TOKEN
      }
    4. Follow response checks before continuing.

Check the REST Response

  1. Confirm that the profile request succeeds with HTTP 200. If it is rejected, follow authentication help and check the profile prerequisites.

  2. Check that the profile belongs to the intended user. This illustrative response shows an enabled user without user-management, group-management, or Priority Talk capabilities:

    {
      "radioUserId": "b4c6d8e0f2a3417b9c1d3e5f708192a3",
      "displayName": "First and Last Name",
      "email": "first.last@example.org",
      "capabilities": {
        "manageUsers": false,
        "manageGroups": false,
        "priorityTalk": false
      }
    }
  3. Continue to Step 8 only after confirming the identity. The capability values control the corresponding application features; a successful profile request doesn't grant access to every Radio operation.

Step 8: Open a WebSocket Session

Use the supported application or implement the authenticated connection sequence below. REST registration and a successful profile request do not establish a live WebSocket session.

The user must be enabled and have radio.channel.list for this authentication sequence. Subsequent channel actions also require their operation-specific permissions and channel access.

  • The application handles WebSocket authentication and messages; you don't enter protocol frames manually.

    1. Finish registration and sign-in in the supported mobile application as described in Step 6.

    2. Select an accessible channel and follow channel use to join and connect.

    For an integration that opens its own connection, use the WebSocket API tab.

  • Use the same Public Safety and Security instance and the installation registered in Step 6.

    1. Construct the WebSocket URL from serviceEndpoint: change https to wss, keep the hostname and any explicitly supplied port, and replace /api/ with /ws/radio.

      wss://<unique-id>.pss.<region>.oci.oraclecloud.com/ws/radio

      The registration descriptor's radioBaseUrl can also supply the origin. See URL construction for a code example.

    2. Use the supported mobile client's WebSocket API to open that URL. Set the following upgrade header to the device ID returned in Step 6. The example uses the same illustrative ID as the registration response.

      X-Oracle-Radio-Device-Id: a3b5c7d9e1f2406a8b0c2d4e6f8091a2

      The device ID identifies the registered installation. Supply the ID returned by registration completion exactly once; a malformed, repeated, or unknown supplied ID causes authentication to fail. Send the access token in the next message; an Authorization upgrade header doesn't authenticate this bearer-token connection.

    3. After the connection opens, send this JSON text message with the current access token obtained through Step 5. Use the token held by the application; the temporary shell token variable from Step 7 has been cleared.

      {
        "type": "AUTH",
        "token": "<access-token>"
      }

      Wait for this response before sending other Radio operations:

      {
        "type": "AUTH_SUCCESS"
      }

      For a device-bound connection, AUTH_SUCCESS can also include audioReadiness timing values. Before receiving live audio, follow readiness reporting; PONG and device heartbeat are not readiness reports.

      If the server returns AUTH_ERROR, stop this sequence and follow authentication help. Don't log the AUTH message or its token.

    4. Send a session-information request on the authenticated connection:

      {
        "type": "WHO_AM_I"
      }

      This illustrative response excerpt identifies the signed-in user. Verify the identity returned for your user. The user value is a username; it isn't the REST profile's radioUserId.

      {
        "type": "WHO_AM_I",
        "authenticated": true,
        "user": "alex.morgan"
      }

      Inspect the returned connection state as described in session information.

    5. Send an application-message connection check:

      {
        "type": "PING"
      }

      Expect PONG. The timestamp below is illustrative.

      {
        "type": "PONG",
        "timestamp": "2026-09-15T15:00:00Z"
      }

      PONG confirms message exchange. It doesn't replace AUTH_SUCCESS; PING is also available before authentication.

    The application has now registered its installation, verified REST access, and authenticated and checked its WebSocket session. Server events can arrive between direct responses; handle messages by their type. To exchange channel messages, continue with joining a channel. For renewal and reconnecting, follow session lifecycle.