Forum Discussion

Cole_McDonald's avatar
Cole_McDonald
Icon for Professor rankProfessor
3 months ago
Solved

RestAPI Alerts access to ExternalTicketID

Has anyone figured out how to get at the ##ExternalTicketID## programatically at all?  Not having access to that is driving me to distraction.  It's in the DB somewhere, but we can't get to it to help automate our workflows and toolsets.

Right now, I'm troubleshooting our Connectwise Integration and have to manually relate 4637 integration log entries to tickets manually one by one.

Only having this internal var being able to be exposed in the Alerts view is hobbling our ability to build and troubleshoot our integrated systems.

  • Dave_Lee's avatar
    Dave_Lee
    2 months ago

    I'm using X-Version=3 as well.  Looks like you're using PowerShell, here's a snippet that's working for me.

    $company = "your-lm-company"  # Replace with your LogicMonitor company name
    $bearerToken = "your-lm-bearer-token" # replace with your LM bearer token
    $daysAgo = 2  # Number of days to look back for alerts
    
    # calculates the epoch time for the start of the query
    $startEpoch = (Get-Date (Get-Date).AddDays(-$daysAgo) -UFormat %s) 
    
    # query string includes the ##EXTERNALTICKETID# custom column and filters for alerts created after the startEpoch.  
    # This Will get the first 1000 results, you'll need to put a loop in to handle paging if you expect  more than that.
    $queryString = ('?customColumns=%23%23EXTERNALTICKETID%23%23&size=1000&offset=0&filter=startEpoch>:' + $startEpoch)
    
    $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
    $headers.Add("Authorization","Bearer $bearerToken")
    $headers.Add("X-Version",'3')
    $headers.Add("Content-Type",'application/json')
    
    $alerts = (Invoke-RestMethod -Uri "https://$company.logicmonitor.com/santaba/rest/alert/alerts$queryString" -Method "GET" -Headers $headers).items
    
    # Filter the alerts to only include those that went to a rule where the name includes "Service Now" and that were not suppressed (e.g. not SDT at the time)
    # Does a bit of manipulation to extract the ServiceNow Incident ID from the custom column ##EXTERNALTICKETID##
    $alerts | where-object {$_.rule -like "*Service Now*" -And !($_.suppressor)} | Select-Object `
        @{Name="Alert ID";Expression={$_.id}}, `
        @{Name="InternalId";Expression={$_.InternalId}}, `
        @{Name="External_Ticket_ID_RAW";Expression={$_.customColumns.'##EXTERNALTICKETID##'}}, `
        @{Name="SNOWIncidentId";Expression={$_.customColumns.'##EXTERNALTICKETID##'.split(':')[1].trim()}}, `
        @{Name="SNOWLinks";Expression={$_.alertExternalTicketUrl.'servicenowIncidentLinks'}}

    You'll need to change (or remove) the filter I've put in for $_.rule -like "*Service Now*" to match whatever your rules are.  You should get something like the output below.

    Alert ID               : DS8871637
    InternalId             : LMD33542811
    External_Ticket_ID_RAW : ServiceNow xxxx : INC5147309
    SNOWIncidentId         : INC5147309
    SNOWLinks              : @{INC5147309=https://xxxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3D82fa6f601bb22a507f1da608b04bcbb9}
    
    Alert ID               : DS8871639
    InternalId             : LMD33542820
    External_Ticket_ID_RAW : ServiceNow xxxxx : INC5147311
    SNOWIncidentId         : INC5147311
    SNOWLinks              : @{INC5147311=https://xxxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3Dab1b27241b766ad006c94043b24bcb1e}
    
    Alert ID               : DS8871640
    InternalId             : LMD33542817
    External_Ticket_ID_RAW : ServiceNow xxxxx : INC5147312
    SNOWIncidentId         : INC5147312
    SNOWLinks              : @{INC5147312=https://xxxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3Dfd7b6b241bb22a507f1da608b04bcb49}

     

21 Replies

  • I don't have a solution for this, but also would like to see this as a way to fully integrate between LM and CW.

  • Try "%23%23externalticketid%23%23" (aka without the "25"s).

    "%23" coverts to "#" so you want it to be "##externalticketid##". I think the forum might have messed up some archived posts by converting "%" to "%25" so that "%2523" would convert to "%23" literally.

    • Cole_McDonald's avatar
      Cole_McDonald
      Icon for Professor rankProfessor

      Sarah_Terry​ , Do you know if they've removed the ##externalticketid## property access through the RestAPI?  you were the hero in the older thread Mike found... Feels like access existed in V1, but doesn't in V3.

      • Asawari's avatar
        Asawari
        Icon for Employee rankEmployee

        Cole_McDonald​ 
        LM has added support to fetch custom columns in V3 alerts API.
        Please try it out and let us know your feedback thanks.

  • For what I'm currently trying to accomplish... this working would help as well:

    It fails... have to get them from the interface directly and export to CSV... also doesn't show the externalticketid in the output, but does in the interface.  Only if you click into each though... so no way to see that data in bulk currently to evaluate behavior of the integration effectively.

  • I used to pull this information by adding the following to the query string:

    customColumns=%23%23EXTERNALTICKETID%23%23

    which would give you an external "customColumns" object in the returned payload with the fields you request, then you could parse ##EXTENRALTICKETID## by splitting by the colon char and strip the leading space.

    "customColumns": { "##EXTERNALTICKETID##": "SCC ServiceNow Integration : INC5132740" }

    I've just had a look to see if you could do the same with alertExternalTicketURL but it seems to be in the default output

    {
      "id": "DS8824603",
      "ruleId": 30,
      "alertExternalTicketUrl": {
        "servicenowIncidentLinks": {
          "INC5132740": "https://xxxxxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3Db05f563a1b962a10438ced79b04bcb81"
        }
      },
      "tenant": "undefined",
      "alertValue": "1.0",
      "sdted": false,
      "SDT": null,
    }

     

    • Cole_McDonald's avatar
      Cole_McDonald
      Icon for Professor rankProfessor

      Still no return.  Here's the full (nearly) RestAPI URL I'm using:

      ********.logicmonitor.com/santaba/rest/alert/alerts?customColumns=%23%23EXTERNALTICKETID%23%23&size=1000&offset=0

      I get a full return of alerts, filter to ones that would have ticketed in connectwise and should have an EXTERNALTICKETID value present.  There is no extra property returned in any of them

  • I am passing the x-version=3... let me comment that out and see if it grabs that data for me.

    That returns nothing.  Are you passing a different value for the version?

    • Dave_Lee's avatar
      Dave_Lee
      Icon for Advisor rankAdvisor

      I'm using X-Version=3 as well.  Looks like you're using PowerShell, here's a snippet that's working for me.

      $company = "your-lm-company"  # Replace with your LogicMonitor company name
      $bearerToken = "your-lm-bearer-token" # replace with your LM bearer token
      $daysAgo = 2  # Number of days to look back for alerts
      
      # calculates the epoch time for the start of the query
      $startEpoch = (Get-Date (Get-Date).AddDays(-$daysAgo) -UFormat %s) 
      
      # query string includes the ##EXTERNALTICKETID# custom column and filters for alerts created after the startEpoch.  
      # This Will get the first 1000 results, you'll need to put a loop in to handle paging if you expect  more than that.
      $queryString = ('?customColumns=%23%23EXTERNALTICKETID%23%23&size=1000&offset=0&filter=startEpoch>:' + $startEpoch)
      
      $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
      $headers.Add("Authorization","Bearer $bearerToken")
      $headers.Add("X-Version",'3')
      $headers.Add("Content-Type",'application/json')
      
      $alerts = (Invoke-RestMethod -Uri "https://$company.logicmonitor.com/santaba/rest/alert/alerts$queryString" -Method "GET" -Headers $headers).items
      
      # Filter the alerts to only include those that went to a rule where the name includes "Service Now" and that were not suppressed (e.g. not SDT at the time)
      # Does a bit of manipulation to extract the ServiceNow Incident ID from the custom column ##EXTERNALTICKETID##
      $alerts | where-object {$_.rule -like "*Service Now*" -And !($_.suppressor)} | Select-Object `
          @{Name="Alert ID";Expression={$_.id}}, `
          @{Name="InternalId";Expression={$_.InternalId}}, `
          @{Name="External_Ticket_ID_RAW";Expression={$_.customColumns.'##EXTERNALTICKETID##'}}, `
          @{Name="SNOWIncidentId";Expression={$_.customColumns.'##EXTERNALTICKETID##'.split(':')[1].trim()}}, `
          @{Name="SNOWLinks";Expression={$_.alertExternalTicketUrl.'servicenowIncidentLinks'}}

      You'll need to change (or remove) the filter I've put in for $_.rule -like "*Service Now*" to match whatever your rules are.  You should get something like the output below.

      Alert ID               : DS8871637
      InternalId             : LMD33542811
      External_Ticket_ID_RAW : ServiceNow xxxx : INC5147309
      SNOWIncidentId         : INC5147309
      SNOWLinks              : @{INC5147309=https://xxxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3D82fa6f601bb22a507f1da608b04bcbb9}
      
      Alert ID               : DS8871639
      InternalId             : LMD33542820
      External_Ticket_ID_RAW : ServiceNow xxxxx : INC5147311
      SNOWIncidentId         : INC5147311
      SNOWLinks              : @{INC5147311=https://xxxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3Dab1b27241b766ad006c94043b24bcb1e}
      
      Alert ID               : DS8871640
      InternalId             : LMD33542817
      External_Ticket_ID_RAW : ServiceNow xxxxx : INC5147312
      SNOWIncidentId         : INC5147312
      SNOWLinks              : @{INC5147312=https://xxxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3Dfd7b6b241bb22a507f1da608b04bcb49}

       

      • Dave_Lee's avatar
        Dave_Lee
        Icon for Advisor rankAdvisor

        Or if you want a more clean URL (ok, I had to ask AI how to do this bit!) then you can use the following:

        $alerts | where-object {$_.rule -like "*Service Now*" -And !($_.suppressor)} | Select-Object `
            @{Name="Alert ID";Expression={$_.id}}, `
            @{Name="InternalId";Expression={$_.InternalId}}, `
            @{Name="External_Ticket_ID_RAW";Expression={$_.customColumns.'##EXTERNALTICKETID##'}}, `
            @{Name="SNOWIncidentId";Expression={$_.customColumns.'##EXTERNALTICKETID##'.split(':')[1].trim()}}, `
            @{Name="SNOWLink"; Expression={
                $_.alertExternalTicketUrl.servicenowIncidentLinks.PSObject.Properties |
                    Select-Object -First 1 | ForEach-Object { $_.Value }
            }}

        that will get you something like this

        Alert ID               : LL104713609
        InternalId             : LML1960249111
        External_Ticket_ID_RAW : ServiceNowxxxxx : INC5147303
        SNOWIncidentId         : INC5147303
        SNOWLink               : https://xxxx.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3D45756be01b722a14d1feeac8b04bcb42


        I think you're using ConnectWise rather than Service Now aren't you?  I'm assuming that LM stores the ConnectWise URLs in the same way so maybe you can adapt it to pull the URLs out.