Welcome to the API Developers Guide. This will cover most of the important concepts when using the API. Other details about the entities such as company, user, and notification filters can be found in the Portal user guide. CTCI Portal
This developer guide covers important points about using the API - Authentication, Error Handling, and such.
The server endpoint for requests is https://api.ctci.ai. There will be a dev sandbox version available soon.
Currently, all endpoints for requests use: /api/v1/<entity>
.
The REST is our architectural standard for our API; it makes it easy to understand and easier to integrate into systems. In entity names, we are using the singular, not the plural. We use user and not users, as we think of an entity as being both singular and plural like a database table.
HTTP VERB | Operation |
---|---|
GET | Is to retrieve one or more entries. Example: GET https://api.ctci.ai/api/v1/user retrieves all users. |
POST | For the creation of an entity such as user, company, notification filter, notification group, notification delivery, processed, etc. |
PUT | This is used to update entries. Example: PUT https://api.ctci.ai/api/v1/user/<id> would update the user with the <id> |
DELETE | This is used to delete an entry. Example: DELETE https://api.ctci.ai/api/v1/user/<id> would delete the user with the <id> |
To view the Swagger API, https://swagger.ctci.ai/
To use the Swagger/OAS specification in your tools, then use this URL. https://raw.githubusercontent.com/vmcommunity/swagger-api/main/cewl_download_swagger.yaml
If you want to generate client code for this then, go to https://editor.swagger.io/, and use the File menu and use open URL, then use the swagger URL above. Postman works well for testing this API as well - the code snippets in this document were generated from Postman.
For the API, you need to have credentials.
How to get your credentials:
The preferred way: your company has been created by the CTCI team. If you want to start a trial, then send an email to sales@ctci.ai. Then register yourself as a user with an email address the same as the company email domain. You will then be able to log in and view the API tokens for your company. Depending on whether you have a CEWL subscription, is whether you see the full CEWL list or the restricted list. Tokens
Register as a user, confirm your address and then perform a login API request with your user name and password. your username and password. This will give you restricted access to the CEWL list - only the NSA Chinese State Actors list. CTCI Portal We call this the JWT tokens for API.
Authentication Tokens must be sent in every request. The examples below are to download the CEWL list.
With API Tokens, you need to set a header “x-api-key” with your API Token from the https://portal.ctci.ai. Examples are shown below. API Tokens cannot be used for interactive login using the CTCI Portal as they are only allowed for API.
curl --location --request GET 'https://api.ctci.ai/api/v1/cewl' \ --header 'x-api-key: <Put the API Token here>' |
# it needs requests import json import requests from os import environ import pandas as pd # grabs the CEWL API Token from environment variables, use whatever mechanism you want for secretes # TODO add your own exception handling around requests url = "https://api.ctci.ai/api/v1/cewl?q=" # empty filter will just download all of CEWL #query_filter = '' # put whatever you need in the query string query_filter = 'vendor="microsoft"' payload={} headers = { 'x-api-key': environ['CEWL_API_TOKEN'] } # TODO put in your exception handling with try_except around the requests call. response = requests.request("GET", f'{url}{query_filter}', headers=headers, data=payload) if response.status_code == 200: cve_data = json.loads(response.text) # to see what it returned # print(cve_data) if cve_data: # put it as a pandas dataframe cve_df = pd.DataFrame(cve_data["data"]) # now whatever ya need :) print(cve_df) else: print(f"Error status_code is:{response.status_code}") print("Error in retrieving CEWL entries, check API Token used") print("do your error handling") |
var myHeaders = new Headers(); myHeaders.append("x-api-key", "<Put the API Token here>"); var requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; fetch("https://api.ctci.ai/api/v1/cewl", requestOptions) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log('error', error)); |
This is using the access_token from a login/password authenticated response.
Firstly do a login to get the access_token.
curl --location --request POST 'http://127.0.0.1:5000/api/v1/login' \ --header 'Content-Type: application/json' \ --data-raw '{"username":"<your_username>","password":"<your_password"}' |
import requests import json ACCESS_TOKEN_IDENTIFIER = "access_token" url = "http://127.0.0.1:5000/api/v1/login" payload = json.dumps({ "username": "<username>", "password": "<password>" }) headers = { 'Content-Type': 'application/json' } response = requests.request("POST", url, headers=headers, data=payload) json_response = json.loads(response.text) if "ACCESS_TOKEN_IDENTIFIER" in json_response: access_token = json_response["ACCESS_TOKEN_IDENTIFIER"] |
Then the response will have an access token, use this in the next requests.
{ "access_token": "<access token>", "id": 6000, "firstname": "Joe", "lastname": "Bloggs", "nickname": "Joey", "roles": "admin" } |
curl --location --request GET 'https://api.ctci.ai/api/v1/cewl' \ --header 'Authorization: Bearer <access token>' |
import requests url = "https://api.ctci.ai/api/v1/cewl" payload={} headers = { 'Authorization': 'Bearer <Put access_token here>' } response = requests.request("GET", url, headers=headers, data=payload) print(response.text) |
var myHeaders = new Headers(); myHeaders.append("Authorization", "Bearer <Put access_token here>"); var requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; fetch("https://api.ctci.ai/api/v1/cewl", requestOptions) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log('error', error)); |
Where possible, we try to adhere to best practice standards for REST, and we try to adhere to good standards in error handling.
For HTTP Errors, we follow, where possible, the Problem Details for HTTP APIs: HTTP APIs (RFC 7807)
https://datatracker.ietf.org/doc/html/rfc7807
Basically, this standard has some common values on errors, and then you can add your own specific error values.
We support:
Problem Details Fields RFC 7807 | CTCI API |
---|---|
status | Used - it’s the HTTP return status |
title | The summary of the response |
detail | More information about the response |
type | Type of error |
instance | This is the request path |
parameter | any specific value that is sent in the request that may help to diagnose the error |
data | Used only on success, this is the JSON of the response for the successful request. |
{"status": 400, "title": "The user does not exist", "detail": "The user with user_id:999999 does not exist", "type": "Bad Request", "instance": "/api/v1/user/999999", "parameter": 999999} |
The successful response uses a lot of fields as the error response, and it has an extra field, “data,” which carries the data about the request. Data is JSON.
A special note: if you try to update fields that you don’t have access to, it won’t update these fields, and if the request is properly formatted will return successfully. This was done as different fields that can be updated are dynamically determined by roles and such. This condition may change in the future and be an error.
{"status": 200, "title": "List of users successful", "detail": "List of users successful", "type": "User", "instance": "/api/v1/user", "parameter": "", "data" : {"json response of the entities"}} |