Community
Questions Library
Docs
Blog
Events
Swag
Github
Slack
JupiterOne
Discussions
Release Notes
Contact Us
JupiterOne API - AskJ1 Community
<main> <article class="userContent"> <p>The JupiterOne platform exposes a number of public GraphQL endpoints.</p> <p><strong>Base URL</strong>: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">https://api.us.jupiterone.io</code></p> <p><strong>Endpoint for query and graph operations</strong>: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/graphql</code></p> <p><strong>Endpoint for alert and rules operations</strong>: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/rules/graphql</code></p> <p><strong>Rate Limits</strong>: Rate limiting is enforced based on your account tier. A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">429</code> HTTP response code indicates the limit has been reached. The API does not currently return any rate limit headers.</p> <p><strong>Authentication</strong>: The JupiterOne APIs use a Bearer Token to authenticate. Include the API key in the header as a Bearer Token. You also need to include <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JupiterOne-Account</code> as a header parameter. You can find the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Jupiterone-Account</code> value in your account by running the following J1QL query:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">FIND jupiterone_account as a return a._accountId </pre> <p><strong>Example cURL command with authentication</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">curl --location --request POST '<a href="https://api.us.jupiterone.io/graphql'" rel="nofollow">https://api.us.jupiterone.io/graphql'</a> \ --header 'JupiterOne-Account: accountId' \ --header 'Authorization: Bearer 123456abcdef' \ --header 'Content-Type: application/json' \ --data-raw '{"query":...} </pre> <p>An experimental <a rel="nofollow" href="https://github.com/JupiterOne/jupiterone-client-nodejs">node.js client and CLI</a> is available on Github.</p> <h2 data-id="entity-and-relationship-queries">Entity and Relationship Queries</h2> <p><strong>Endpoint:</strong> <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/graphql</code></p> <h3 data-id="querying-the-graph-with-j1ql">Querying the graph with J1QL</h3> <p>This query will allow you to run J1QL queries for fetching data. The GraphQL resolver requires that one parameter is provided:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">query</code>: A J1QL query string that describes what data to return</li> </ul><p>Optionally, additional parameters can be provided:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">variables</code>: A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> map of values to be used as parameters for the query</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">cursor</code>: A token that can be exchanged to fetch the next page of information.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">includeDeleted</code>: When set to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">true</code>, recently deleted information will be included in the results.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">deferredResponse</code>: This option allows for a deferred response to be returned. When a deferred response is returned, a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">url</code> pointing the state of the query is provided. API consumers should poll the status of the deferred query by requesting the given <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">url</code> until the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">status</code> property of the returned JSON document has a value of <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">COMPLETED</code> (see example below). Upon completion of the query, the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">url</code> will provide a link to the query results. The results contain the same <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">type</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">data</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">cursor</code> fields that the non-deferred GraphQL response would contain. Allowed values are <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">DISABLED</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FORCE</code>.</li> </ul><p><strong>Note:</strong><br> When paging through data, it is <em>highly</em> recommended that cursors are leveraged instead of adding <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">limit</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">skip</code> clauses to queries.</p> <p><strong>Note:</strong><br> Be sure to include <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">cursor</code> in the GraphQL response if you need to paginate through the results. The returned <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">cursor</code> will be <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">null</code> if there are no more pages available.</p> <p><strong>Note:</strong><br> Queries that may take longer than 30 seconds should use the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FORCE</code> option for <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">deferredResponse</code> to avoid request timeouts. You should only use the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">DISABLED</code> option when testing a simple query. It is <em>highly</em> recommended that all automated processes use the the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FORCE</code> option when issuing J1QL queries.</p> <p><strong>Example GraphQL query:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query J1QL($query: String!, $variables: JSON, $cursor: String) { queryV1(query: $query, variables: $variables, cursor: $cursor) { type data cursor } } </pre> <p><strong>Example variables:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "query": "find Person with _type=${type} return Person.name", "variables": { "type": "employee" }, "cursor": "eyJjYWNoZUtleSI6IjFlNDg3MT..." } </pre> <p><strong>Example <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryV1</code> resolver result:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "table", "data": [{ "Person.name": "Mochi" }], "cursor": "eyJjYWNoZUtleSI6IjFlNDg3MT..." } </pre> <p><strong>Example GraphQL query using with deferred responses:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query J1QL( $query: String! $variables: JSON $cursor: String $deferredResponse: DeferredResponseOption ) { queryV1( query: $query variables: $variables deferredResponse: $deferredResponse cursor: $cursor ) { type url } } </pre> <p><strong>Example variables:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "query": "find Person with _type=${type}", "deferredResponse": "FORCE", "variables": { "type": "employee" }, "cursor": "eyJjYWNoZUtleSI6IjFlNDg3MT..." } </pre> <p><strong>Example <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryV1</code> resolver result when using a deferred response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "type": "deferred", "url": "<a href="https://example.com/state.json" rel="nofollow">https://example.com/state.json</a>" } </pre> <p><strong>Example state responses:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "status": "IN_PROGRESS", "correlationId": "912788f1-e0c7-43bd-b853-455c0031be8a" } </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "status": "COMPLETED", "url": "<a href="https://example.com/results.json" rel="nofollow">https://example.com/results.json</a>", "correlationId": "912788f1-e0c7-43bd-b853-455c0031be8a" } </pre> <h3 data-id="fetching-graph-data">Fetching Graph Data</h3> <p>You can use this query to fetch graph data. The returned data includes the details of all vertices found on the graph, as well as the relationship edges that connect the vertices.</p> <p><strong>Note:</strong><br> Currently, a canned query for IAM Role data is run. You do not need to provide any input variables.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery { queryGraph { vertices { id entity { _id _key _type _accountId _integrationName _integrationDefinitionId _integrationInstanceId _version _createdOn _beginOn _endOn _deleted displayName } properties } edges { id toVertexId fromVertexId relationship { _id _key _type _accountId _integrationName _integrationDefinitionId _integrationInstanceId _version _createdOn _beginOn _endOn _deleted _fromEntityKey _toEntityKey displayName } properties } } } </pre> <h3 data-id="retrieving-a-single-vertex-by-id">Retrieving a Single Vertex by ID</h3> <p>This query fetches a vertex and its properties by its ID. The query requires one of two parameters:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>: The ID as a string</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filters</code>: A set of filters that define the desired vertex.</li> </ul><p>The example below contains all of the currently available filters.</p> <p><strong>Note:</strong><br> Only one of the variables (<code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filters</code>) is required. Specifying both is allowed but unnecessary unless you want to assert that a vertex with the specified <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> exists <em>and</em> has specific entity properties.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query VertexQuery($id: String!, $filters: VertexFilters) { vertex(id: $id, filters: $filters) { id entity { _id _key _type _accountId _integrationName _integrationDefinitionId _integrationInstanceId _version _createdOn _beginOn _endOn _deleted displayName } properties } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "<a vertex id>", "filters": { "_id": "<an entity id>", "_key": "<an entity key>", "_type": ["<a entity type>"], "_class": ["<a entity class>"] } } </pre> <h3 data-id="fetching-neighbors-of-a-vertex">Fetching Neighbors of a Vertex</h3> <p>The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Vertex</code> type allows you to retrieve vertex and edge neighbors up to a certain depth using the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">neighbors</code> field. The return type of the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">neighbors</code> resolver is the same as that of a graph query. This query requires two parameters:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>: The ID of the vertex as a string</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">depth</code>: An integer specifying how many "levels" deep the query will go to look for neighbors.</li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">query VertexQuery($id: String!, $depth: Int) { vertex(id: $id) { id entity { displayName } neighbors(depth: $depth) { vertices { id entity { displayName } } edges { id relationship { displayName } } } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "<a vertex id>", "depth": 5 } </pre> <p><strong>Note:</strong><br> The depth that is supplied must be a value between 1 and 5 (inclusive).</p> <h3 data-id="retrieving-an-edge-by-id">Retrieving an Edge by ID</h3> <p>This query allows you to fetch an edge, its properties, and the relationship it describes by its ID or label and filters. The query requires one or two of three parameters:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>: The ID as a string.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">label</code>: The label displayed on the edge.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filters</code>: A set of filters that define the desired vertex.</li> </ul><p>The example below contains all of the currently available filters.</p> <p><strong>Note:</strong><br> Only one of the variables (<code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">label</code>, or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filters</code>) is required. Specifying <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">label</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filters</code> with <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> is allowed but somewhat redundant unless you want to assert that a vertex with the specified <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> exists <em>and</em> has the specific label and properties.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query VertexQuery($id: String!) { edge(id: $id, label: $id, filters: $id) { id relationship { _id _key _type _accountId _integrationName _integrationDefinitionId _integrationInstanceId _version _createdOn _beginOn _endOn _deleted _fromEntityKey _toEntityKey displayName } properties } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "<an edge id>", "label": "<edge label>", "filters": { "_id": "<a relationship id>", "_key": "<a relationship key>", "_type": "<a relationship type>", "_class": "<a relationship class>" } } </pre> <h3 data-id="fetching-the-count-of-entities-via-a-type-and-or-class">Fetching the Count of Entities Via a _type and/or _class</h3> <p>This query allows you to fetch the count of entities. The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_id</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_key</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_type</code>, or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_class</code> fields can be supplied as filters. This query only counts the latest versions of entities matching the filter criteria. This query requires two parameters:</p> <ul><li><p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filters</code>: A set of vertex filters that describe the entities that are to be<br> returned.</p></li> <li><p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filterType</code>: A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FilterType</code> (<code class="code codeInline code codeInline" spellcheck="false" tabindex="0">AND</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">OR</code>).</p></li> </ul><p>If <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">OR</code> is specified as the filter type, any entity that has any class in the filter will be included in the count. By default, the query uses <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">AND</code>, which only includes entities that have <em>all</em> of the specified classes in the count.</p> <p><strong>Note:</strong><br> This resolver uses the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> scalar as the return type.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery($filters: VertexFilters, $filterType: FilterType) { entityCount(filters: $filters, filterType: $filterType) } </pre> <p><strong>Note:</strong><br> Use field aliases to request the counts of multiple different entities.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery { Users: entityCount(filters: { _class: ["User"] }, filterType: "AND") Repos: entityCount(filters: { _class: ["CodeRepo"] }, filterType: "OR") } </pre> <p>Example result:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "User": 40, "CodeRepo": 153 } </pre> <h3 data-id="fetching-the-count-of-all-types-and-classes">Fetching the Count of All Types and Classes</h3> <p>This query returns the entity counts for all types and classes.</p> <p><strong>Note:</strong><br> This resolver uses the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> scalar as the return type.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery { allEntityCounts } </pre> <p>Example result:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "typeCounts": { "iam_user": 12, "iam_managed_policy": 10, "iam_role_policy": 10 }, "classCounts": { "User": 12, "AccessPolicy": 20 } } </pre> <h3 data-id="fetching-the-count-of-all-types-with-a-set-of-classes">Fetching the Count of All Types With a Set of Classes</h3> <p>This query returns all types that have the specified classes. The query requires two parameters:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">classes</code>: An array of strings detailing which classes should be returned.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filterType</code>: A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FilterType</code> (<code class="code codeInline code codeInline" spellcheck="false" tabindex="0">AND</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">OR</code>).</li> </ul><p>If <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">OR</code> is specified as the filter type, any entity that has any class in the filter will be included in the count. By default, the query uses <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">AND</code>, which only includes entities that have <em>all</em> of the specified classes in the count.</p> <p><strong>Note:</strong><br> This resolver uses the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> scalar as the return type.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery ($classes: [String], filterType: FilterType) { typeCounts (classes: $classes, filterType: $filterType) } </pre> <p>Example result:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "iam_user": 12, "iam_managed_policy": 10, "iam_role_policy": 10 } </pre> <h3 data-id="listing-vertices-via-a-type-and-or-class">Listing Vertices Via a _type and/or _class</h3> <p>For fetching entities with specified filters. The <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_id</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_key</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_type</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_class</code> fields can be supplied as filters. This query only returns the latest versions of entities matching the filter criteria. This query accepts three parameters:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filters</code>: A set of vertex filters that describe the entities to return (required).</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">after</code>: A string to begin searching after (required).</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">filterType</code>: A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FilterType</code> (<code class="code codeInline code codeInline" spellcheck="false" tabindex="0">AND</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">OR</code>).</li> </ul><p>If <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">OR</code> is specified as the filter type, any entity that has any class in the filter will be included in the count. By default, the query uses <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">AND</code>, which only includes entities that have <em>all</em> of the specified classes in the count.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery($filters: VertexFilters, $filterType: FilterType, $after: String) { listVertices(filters: $filters, filterType: $filterType, after: $after) { vertices { id entity { // entity details here } properties } total pageInfo { endCursor hasNextPage } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "filters": { "_type": ["<an entity type>"], "_class": ["<an entity class>"] }, "filterType": "<AND or OR>", "after": "the value of pageInfo.endCursor" } </pre> <p>Example result</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "vertices": [ { "id": "some-id", "entity": { "displayName": "Laptop-2345" } } ], "total": 1, "pageInfo": { "endCursor": "some-base64-cursor", "hasNextPage": true } } </pre> <h2 data-id="entity-mutations">Entity Mutations</h2> <p><strong>Endpoint:</strong> <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/graphql</code></p> <h3 data-id="create-entity">Create Entity</h3> <p>This mutation creates a JupiterOne entity with the given specifications. This mutation requires three parameters (with two optional parameters):</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityKey</code>: A string that gives the key value for the entity so that this entity can be referenced later.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityType</code>: A string that gives the type of the entity being created.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityClass</code>: A string that gives the class of the entity being created.</li> <li>Optional Parameters <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">timestamp</code>:</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">properties</code>: A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> list that gives specific properties that the entity will have.</li> </ul></li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">mutation CreateEntity ( $entityKey: String! $entityType: String! $entityClass: String! $timestamp: Long $properties: JSON ) { createEntity ( entityKey: $entityKey, entityType: $entityType, entityClass: $entityClass, timestamp: $timestamp, properties: $properties ) { entity { _id ... } vertex { id, entity { _id ... } properties } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "entityKey": "<an entity key>", "entityType": "<an entity type>", "entityClass": "<an entity class>", "timestamp": 1529329792552, "properties": { // Custom properties on the Entity ... } } </pre> <h3 data-id="updating-entity">Updating Entity</h3> <p>This mutation updates an already existing entity (does not create an entity). You cannot change the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityKey</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityClass</code>, or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityType</code>. This mutation requires one parameter (with two optional parameters):</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityId</code>: A string specific to the entity that finds the entity.</li> <li>Optional Parameters: <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">timestamp</code>:</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">properties</code>: A <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> list of properties to be changed.</li> </ul></li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">mutation UpdateEntity ( $entityId: String! $timestamp: Long $properties: JSON ) { updateEntity ( entityId: $entityId, timestamp: $timestamp, properties: $properties ) { entity { _id ... } vertex { id, entity { _id ... } properties } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "entityId": "<an entity Id (entity._id)>", "timestamp": 1529329792552, "properties": { // Custom properties to get updated ... } } </pre> <h3 data-id="deleting-entity">Deleting Entity</h3> <p>This mutation deletes an existing entity. This mutation requires one parameter (with one optional parameter):</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">entityId</code>: A string specific to the entity that finds the entity.</li> <li>Optional Parameters: <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">timestamp</code>:</li> </ul></li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">mutation DeleteEntity ( $entityId: String! $timestamp: Long ) { deleteEntity ( entityId: $entityId, timestamp: $timestamp, ) { entity { _id ... } vertex { id, entity { _id ... } properties } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "entityId": "<an entity Id (entity._id)>", "timestamp": 1529329792552 } </pre> <h2 data-id="relationship-mutations">Relationship Mutations</h2> <p><strong>Endpoint:</strong> <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/graphql</code></p> <h3 data-id="create-relationship">Create Relationship</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation CreateRelationship ( $relationshipKey: String! $relationshipType: String! $relationshipClass: String! $fromEntityId: String! $toEntityId: String! $timestamp: Long $properties: JSON ) { createRelationship ( relationshipKey: $relationshipKey, relationshipType: $relationshipType, relationshipClass: $relationshipClass, fromEntityId: $fromEntityId, toEntityId: $toEntityId, timestamp: $timestamp, properties: $properties ) { relationship { _id ... } edge { id toVertexId fromVertexId relationship { _id ... } properties } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "relationshipKey": "<a relationship key>", "relationshipType": "<a relationship type>", "relationshipClass": "<a relationship class>", "fromEntityId": "<the _id of the from entity>", "toEntityId": "<the _id of the to entity>", "timestamp": 1529329792552, "properties": { // Custom properties on the relationship ... } } </pre> <h3 data-id="update-relationship">Update Relationship</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation UpdateRelationship ( $relationshipId: String! $timestamp: Long $properties: JSON ) { updateRelationship ( relationshipId: $relationshipId, timestamp: $timestamp, properties: $properties ) { relationship { _id ... } edge { id toVertexId fromVertexId relationship { _id ... } properties } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "relationshipId": "<a relationship Id (relationship._id)>", "timestamp": 1529329792552, "properties": { // Custom properties to get updated ... } } </pre> <h3 data-id="delete-relationship">Delete Relationship</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation DeleteRelationship ( $relationshipId: String! $timestamp: Long ) { deleteRelationship ( relationshipId: $relationshipId, timestamp: $timestamp, ) { relationship { _id ... } edge { id toVertexId fromVertexId relationship { _id ... } properties } } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "relationshipId": "<a relationship Id (relationship._id)>", "timestamp": 1529329792552 } </pre> <h2 data-id="entity-and-relationship-synchronization-bulk-upload">Entity and Relationship Synchronization (Bulk Upload)</h2> <p>An integration job is responsible for sending all of the latest entities and relationships to the persister and the persister will compare the <em>new state</em> to the <em>old state</em> and automatically apply the changes to the graph.</p> <p>The persister exposes a public REST API that will be used when developing, testing, and running integrations outside the JupiterOne cloud infrastructure.</p> <p>The synchronization API also supports synchronizing a <em>grouping</em> of entities and relationships from an API source by using a <em>scope</em> property. That is, a group of entities and relationships can be logically grouped together by an arbitrary scope value and uploaded to the persister via the synchronization API and the<br> create, update, and delete operations will be automatically determined within the given scope. The scope value is stored on the entities and relationships in the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_scope</code> property.</p> <h3 data-id="integration-job-bookkeeping">Integration Job Bookkeeping</h3> <p>While an integration job is running, the persister will need to keep track of data as the job progresses.</p> <p>This information will be tracked:</p> <ul><li>New entities</li> <li>New relationships</li> <li>Raw data associated with entities (including <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Content-Type</code>)</li> <li>Job status and progress counters</li> <li>Job metadata (start time, source, etc.)</li> </ul><h3 data-id="phases-of-synchronization">Phases of Synchronization</h3> <ol><li><p><strong>Data Collection:</strong> An integration job or other tools runs and collects all data and stores it temporarily on filesystem.</p></li> <li><p><strong>Data Upload:</strong> All data that represents "new state" is uploaded to the persister and associated with an integration job identifier. The "new state" will consist of entities, relationships, and raw data.</p></li> <li><p><strong>Finalization:</strong> After an integration has uploaded all data to the persister, "finalization" is triggered. During the "finalization" phase, the persister compares the "new state" with the "old state" and determines changes. The persister immediately performs any changes that are detected during the<br> run of the finalization task (they are not queued on a Kinesis stream).</p> <p>Entities are finalized first and relationships are finalized afterward (because relationships might reference new entities).</p></li> </ol><h2 data-id="synchronization-api-usage">Synchronization API Usage</h2> <h3 data-id="request-flags">Request Flags</h3> <p>ignoreDuplicates:</p> <p>Instructs the system to not throw an error if there are graph objects with duplicate keys. This will allow the latest graph object to be created if there are duplicate keys already in use.</p> <h3 data-id="request-body-properties">Request Body Properties</h3> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">source</code>:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">api</code> for ad hoc data.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integration-external</code> for custom integrations.</li> </ul><p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">scope</code>:</p> <ul><li>The Scope value can be set to any string. The same value needs to be used in the future for updating entities/relationships/properties within that scope.</li> <li>Scope is required when the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">syncMode</code> is <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">DIFF</code>.</li> <li>Scope can only be used when the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">source</code> is <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">api</code>.</li> </ul><p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">syncMode</code>:</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">DIFF</code> is the default value when a syncMode is not specified. This mode will update/replace all of the entities/relationships within a specified scope. The full dataset should be provided, otherwise entities and relationships may be unintentionally deleted.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">CREATE_OR_UPDATE</code> should be used when you are editing an existing scope of data. Use this mode when you want to add, update, or delete a subset of entities/relationships.</li> </ul><p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integrationInstanceId</code>:</p> <ul><li>Required when referencing a custom integration (the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">scope</code> is equal to <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">integration-external</code>).</li> </ul><h3 data-id="start-a-synchronization-job">Start a synchronization job</h3> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "source": "api", "scope": "my-sync-job" } </pre> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "source": "integration-managed", "integrationInstanceId": "5465397d-8491-4a12-806a-04792839abe3" } </pre> <p><strong>Sample response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "AWAITING_UPLOADS", "startTimestamp": 1586915139427, "numEntitiesUploaded": 0, "numEntitiesCreated": 0, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 0, "numRelationshipsCreated": 0, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <h3 data-id="get-status-of-synchronization-job">Get status of synchronization job</h3> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">GET /persister/synchronization/jobs/f445397d-8491-4a12-806a-04792839abe3 </pre> <p><strong>Sample response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "AWAITING_UPLOADS", "startTimestamp": 1586915139427, "numEntitiesUploaded": 0, "numEntitiesCreated": 0, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 0, "numRelationshipsCreated": 0, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <h3 data-id="upload-batch-of-entities-and-relationships">Upload batch of entities and relationships</h3> <p>Batch upload accepts the formats: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">json</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">csv</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">yaml</code> sent as text in the<br> request body. The following <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Content-Type</code> request headers should be set<br> according to the intended type:</p> <table><thead><tr><th align="center">Format</th> <th>Content-Type</th> </tr></thead><tbody><tr><td align="center">json</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'application/json'</code></td> </tr><tr><td align="center">yaml</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'application/yaml'</code></td> </tr><tr><td align="center">csv</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'text/csv'</code></td> </tr></tbody></table><p>In the case of a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">csv</code>, the type of graph object ("entity" or "relationship") is<br> inferred by the presence of one or more of the following the columns:<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_fromEntityKey</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_fromEntityId</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_toEntityKey</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_toEntityId</code>.</p> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/f445397d-8491-4a12-806a-04792839abe3/upload </pre> <p><strong>Entity / Relationship JSON:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "entities": [ { "_key": "1", "_class": "DataStore", "_type": "fake_entity", "displayName": "my_datastore" }, { "_key": "2", "_class": "Database", "_type": "fake_entity", "displayName": "my_database" }, { "_key": "3", "_class": "Domain", "_type": "fake_entity", "displayName": "my_domain" } ], "relationships": [ { "_key": "a", "_type": "fake_relationship", "_fromEntityKey": "1", "_toEntityKey": "2" }, { "_key": "b", "_type": "fake_relationship", "_fromEntityKey": "2", "_toEntityKey": "3" } ] } </pre> <p><strong>Entity / Relationship CSV</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">"_type","_class","_key","displayName","_fromEntityKey","_toEntityKey" "<a relationship type>","<a relationship class>","<a relationship key>","my_relationship_name","<an entity key>","<an entity key>" "<a entity type>","<a entity class>","<an entity key>","my_entity_name",, </pre> <p><strong>Sample response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "AWAITING_UPLOADS", "startTimestamp": 1586915752483, "numEntitiesUploaded": 3, "numEntitiesCreated": 0, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 2, "numRelationshipsCreated": 0, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <h3 data-id="upload-batch-of-entities">Upload batch of entities</h3> <p>Batch upload accepts the formats: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">json</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">csv</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">yaml</code> sent as text in the<br> request body. The following <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Content-Type</code> request headers should be set<br> according to the intended type:</p> <table><thead><tr><th align="center">Format</th> <th>Content-Type</th> </tr></thead><tbody><tr><td align="center">json</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'application/json'</code></td> </tr><tr><td align="center">yaml</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'application/yaml'</code></td> </tr><tr><td align="center">csv</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'text/csv'</code></td> </tr></tbody></table><p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/f445397d-8491-4a12-806a-04792839abe3/entities </pre> <p><strong>Upload Entity JSON</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "entities": [ { "_key": "1", "_type": "fake_entity" }, { "_key": "2", "_type": "fake_entity" }, { "_key": "3", "_type": "fake_entity" } ] } </pre> <p><strong>Upload Entity CSV</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">"_type","_class","_key","displayName" "<a entity type>","<a entity class>","<an entity key>","my_entity_name" </pre> <p><strong>Sample response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "AWAITING_UPLOADS", "startTimestamp": 1586915752483, "numEntitiesUploaded": 3, "numEntitiesCreated": 0, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 0, "numRelationshipsCreated": 0, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <h3 data-id="upload-batch-of-relationships">Upload batch of relationships</h3> <p>Batch upload accepts the formats: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">json</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">csv</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">yaml</code> sent as text in the<br> request body. The following <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">Content-Type</code> request headers should be set<br> according to the intended type:</p> <table><thead><tr><th align="center">Format</th> <th>Content-Type</th> </tr></thead><tbody><tr><td align="center">json</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'application/json'</code></td> </tr><tr><td align="center">yaml</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'application/yaml'</code></td> </tr><tr><td align="center">csv</td> <td><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">'text/csv'</code></td> </tr></tbody></table><p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/f445397d-8491-4a12-806a-04792839abe3/relationships </pre> <p><strong>Upload Relationship JSON:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "relationships": [ { "_key": "a", "_type": "fake_relationship", "_fromEntityKey": "1", "_toEntityKey": "2" }, { "_key": "b", "_type": "fake_relationship", "_fromEntityKey": "2", "_toEntityKey": "3" } ] } </pre> <p><strong>Upload Relationship CSV:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">"_type","_class","_key","_id","displayName","_fromEntityKey","_toEntityKey" "<a relationship type>","<a relationship class>","<a relationship key>","my_relationship_name","<an entity key>","<an entity key>" </pre> <p><strong>Sample response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "AWAITING_UPLOADS", "startTimestamp": 1586915752483, "numEntitiesUploaded": 3, "numEntitiesCreated": 0, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 2, "numRelationshipsCreated": 0, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <h3 data-id="csv-upload-data-types">CSV Upload Data Types</h3> <p>JupiterOne will infer primitive types (e.g. strings, numbers, booleans) within<br> columns automatically. If the value can be converted to a number or boolean, it<br> will be converted during the upload process.</p> <p>To include JSON arrays within a csv column, there are two acceptable ways to express these structures:</p> <p><strong>Double Quote Format</strong></p> <p>Use double quotes <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">""</code> to escape quotes within an JSON array. This<br> format is the most common way to express and escape quote characters when<br> embedding JSON within a csv column.</p> <p><em>JSON Array</em>:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">"_type","_class","_key","_id","custom" "my_type","my_class","my_key","my_id","[""my_value"",100,true]" </pre> <p><strong>Column Dot Notation</strong></p> <p>JSON arrays can also be described by using the value's JSON path<br> (via dot notation) within the name of the column. Each element of<br> that JSON array would then receive its own column with a zero indexed number specifying its location in the array.</p> <p><em>JSON Array</em>:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">"_type","_class","_key","_id","custom.0","custom.1","custom.2" "my_type","my_class","my_key","my_id","my_value","100","true" </pre> <p><strong>Sample response:</strong></p> <p><em>JSON Array</em>:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">[ { "_type": "my_type", "_class": "my_class", "_key": "my_key", "_id": "my_id", "custom": ["my_value", 100, true] } ] </pre> <h3 data-id="getting-bulk-upload-urls-for-synchronization-jobs">Getting Bulk Upload URLs for Synchronization Jobs</h3> <p>You can use a bulk upload URL to upload a file that has the same structure as<br> the body of a normal upload request. The persister processes this file during<br> finalization. Currently, the persister only allows one bulk upload per<br> synchronization job. If you request a bulk upload URL more than once, the<br> persister returns the same URL until it expires. Upload URLs expire in one<br> hour.</p> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/f445397d-8491-4a12-806a-04792839abe3/uploadUrl </pre> <p><strong>Sample response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "uploadUrl": "{a very long signed S3 URL}", "expiresAt": 1631198730000 } </pre> <h3 data-id="finalize-synchronization-job">Finalize synchronization job</h3> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/f445397d-8491-4a12-806a-04792839abe3/finalize </pre> <p><strong>Sample response (when running locally):</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "FINISHED", "startTimestamp": 1586915752483, "numEntitiesUploaded": 3, "numEntitiesCreated": 3, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 2, "numRelationshipsCreated": 2, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <p><strong>Sample response (when running in AWS):</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "FINALIZE_PENDING", "startTimestamp": 1586915752483, "numEntitiesUploaded": 3, "numEntitiesCreated": 0, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 2, "numRelationshipsCreated": 0, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <h3 data-id="synchronization-job-status-upon-completion">Synchronization job status upon completion</h3> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">GET /persister/synchronization/jobs/f445397d-8491-4a12-806a-04792839abe3 </pre> <p><strong>Sample response:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "job": { "source": "api", "scope": "my-sync-job", "id": "f445397d-8491-4a12-806a-04792839abe3", "status": "FINISHED", "startTimestamp": 1586915752483, "numEntitiesUploaded": 3, "numEntitiesCreated": 3, "numEntitiesUpdated": 0, "numEntitiesDeleted": 0, "numRelationshipsUploaded": 2, "numRelationshipsCreated": 2, "numRelationshipsUpdated": 0, "numRelationshipsDeleted": 0 } } </pre> <h3 data-id="bulk-update">Bulk Update</h3> <p>Start a new synchronization job:</p> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "source": "api", "syncMode": "CREATE_OR_UPDATE" } </pre> <p>Once the synchronization job is running, use the job id from the response to<br> send a request to update existing entities/relationships.</p> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/<jobId>/upload </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "entities": [ { "_key": "some_entity_id", "_type": "fake_entity", "_class": "MyEntity0", "property0": "value0" }, { "_key": "some_other_entity_id", "_type": "fake_entity", "_class": "MyEntity1", "property1": "value1" } ], "relationships": [ { "_key": "a", "_type": "new_relationship", "_fromEntityKey": "some_entity_id", "_toEntityKey": "some_other_entity_id" } ] } </pre> <p>Last, finalize the job.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/<jobId>/finalize </pre> <h3 data-id="bulk-delete">Bulk Delete</h3> <p>Start a new synchronization job:</p> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "source": "api", "syncMode": "CREATE_OR_UPDATE" } </pre> <p>Once the synchronization job is running, use the job id from the response to<br> send a request to delete existing entities/relationships.</p> <p><strong>Sample request:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/<jobId>/upload </pre> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "deleteEntities": [ { "_id": "example-uuid-01" }, { "_id": "example-uuid-02" }, { "_id": "example-uuid-03" } ], "deleteRelationships": [ { "_id": "example-uuid-04" }, { "_id": "example-uuid-05" }, { "_id": "example-uuid-06" } ] } </pre> <p>Last, finalize the job.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST /persister/synchronization/jobs/<jobId>/finalize </pre> <p>!!! note</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">- When you delete an entity, all of the associated relationships will also be deleted. You do not need to call out both unless you are deleting unrelated relationships. - You can delete by both `_id` and `_key`. We recommend deleting entities by id because the `_id` is unique across all entities. </pre> <h2 data-id="retrieve-entity-metadata-and-versions">Retrieve Entity Metadata and Versions</h2> <p>Before making a request to the following endpoints, update the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">${ENTITY_ID}</code><br> placeholder with the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">_id</code> metadata property of a given entity.</p> <h3 data-id="get-metadata-about-the-latest-raw-data-entries-for-a-given-entity">Get metadata about the latest raw data entries for a given entity</h3> <p><strong>Endpoint</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">GET <a href="https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data" rel="nofollow">https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data</a> </pre> <p><strong>Example Return</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">@{ "entries": { "exampleEntry": { "beginOn": 1579116466000, "contentType": "application/json", "contentLength": 256, "createdOn": 0, "deleted": false, "versionId": "<a href="https://jupiterone.vanillacommunities.com/profile/H7JL4jgxSX9Cv5jTGvbz_xHDiVOKuRvd%22" rel="nofollow">@H7JL4jgxSX9Cv5jTGvbz_xHDiVOKuRvd"</a> } } } </pre> <h3 data-id="get-all-version-metadata-for-raw-data-entries-for-a-given-entity">Get all version metadata for raw data entries for a given entity</h3> <p><strong>Endpoint</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">GET <a href="https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data-versions" rel="nofollow">https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data-versions</a> </pre> <p><strong>Example Return</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "entries": { "exampleEntry1": [ { "beginOn": 1593026714000, "contentType": "application/json", "contentLength": 15, "createdOn": 1593115669000, "deleted": false, "versionId": "id1" } ], "exampleEntry2": [ { "beginOn": 1593114913000, "contentType": "application/json", "contentLength": 18, "createdOn": 1593114913000, "deleted": false, "versionId": "id2" }, { "beginOn": 1593113910000, "contentType": "application/json", "contentLength": 21, "createdOn": 1593114913000, "deleted": false, "versionId": "id1" } ] } } </pre> <h3 data-id="get-version-metadata-for-specific-entry-for-a-given-entity">Get version metadata for specific entry for a given entity</h3> <p>Before making a request to the following endpoints, update the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">${ENTRY_NAME}</code><br> placeholder with one of the example entries returned in the previous example<br> (exampleEntry1/exampleEntry2). Make sure you update the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">${ENTITY_ID}</code> as well<br> like in the previous examples.</p> <p><strong>Endpoint</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">GET <a href="https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data/${ENTRY_NAME}/versions" rel="nofollow">https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data/${ENTRY_NAME}/versions</a> </pre> <p><strong>Example Return</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "versions": [ { "beginOn": 1593114913000, "contentType": "application/json", "contentLength": 18, "createdOn": 1593114913000, "deleted": false, "versionId": "id2" }, { "beginOn": 1593113910000, "contentType": "application/json", "contentLength": 21, "createdOn": 1593114913000, "deleted": false, "versionId": "id1" } ] } </pre> <h3 data-id="download-raw-data-for-a-given-entry-of-a-given-entity">Download raw data for a given entry of a given entity</h3> <p><strong>Endpoint</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">GET <a href="https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data/${ENTRY_NAME}/versions/latest" rel="nofollow">https://api.us.jupiterone.io/entities/${ENTITY_ID}/raw-data/${ENTRY_NAME}/versions/latest</a> </pre> <p><strong>Example Return</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "teamId": "exampleTeamId", "teamName": "jupiterone-demo", "appId": "exampleAppId" } </pre> <h2 data-id="building-csv-report">Building CSV Report</h2> <p><strong>Endpoint:</strong> <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/graphql</code></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation BuildCsv( $filters: VertexFilters $propertyFilters: JSON $filterType: FilterType ) { buildCsv( filters: $filters propertyFilters: $propertyFilters filterType: $filterType ) { stateFileUrl } } </pre> <p>Variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "filters": { "_type": ["<an entity type>"], "_class": ["<an entity class>"] }, "filterType": "<AND or OR>", "propertyFilters": { ... } } </pre> <h2 data-id="alert-and-rules-operations">Alert and Rules Operations</h2> <p><strong>Endpoint:</strong> <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/rules/graphql</code></p> <h3 data-id="create-an-inline-alert-rule-from-j1ql">Create an inline alert rule from J1QL</h3> <p>This operation was formerly named <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">createQuestionRuleInstance</code>. That name is<br> now deprecated, and you should update all usages.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation CreateInlineQuestionRuleInstance( $instance: CreateInlineQuestionRuleInstanceInput! ) { createInlineQuestionRuleInstance(instance: $instance) { id name description version pollingInterval question { queries { query version } } operations { when actions } outputs } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "instance": { "name": "unencrypted-prod-data", "description": "Data stores in production tagged critical and unencrypted", "version": "v1", "pollingInterval": "ONE_DAY", "outputs": ["alertLevel"], "operations": [ { "when": { "type": "FILTER", "version": 1, "condition": [ "AND", ["queries.unencryptedCriticalData.total", "!=", 0] ] }, "actions": [ { "type": "SET_PROPERTY", "targetProperty": "alertLevel", "targetValue": "CRITICAL" }, { "type": "CREATE_ALERT" } ] } ], "question": { "queries": [ { "query": "Find DataStore with (production=true or tag.Production=true) and classification='critical' and encrypted!=true as d return d.tag.AccountName as Account, d.displayName as UnencryptedDataStores, d._type as Type, d.encrypted as Encrypted", "version": "v1", "name": "unencryptedCriticalData" } ] } } } </pre> <p>Note that the recommended interval for query based alert rules (aka a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">question</code>)<br> is <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_DAY</code>. \<br> Supported intervals for enterprise customers are:<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">DISABLED</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">THIRTY_MINUTES</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_HOUR</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">FOUR_HOURS</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">EIGHT_HOURS</code>,<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">TWELVE_HOURS</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_DAY</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_WEEK</code>.</p> <p>Free accounts only have access to the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_WEEK</code> interval by default, but<br> any upgrades to Compliance, Security, or Integrations will provide access<br> to the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_DAY</code> polling interval too.</p> <h3 data-id="update-an-inline-alert-rule">Update an inline alert rule</h3> <p>This operation was formerly named <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">updateQuestionRuleInstance</code>. That name is<br> now deprecated, and you should update all usages.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation UpdateInlineQuestionRuleInstance( $instance: UpdateInlineQuestionRuleInstanceInput! ) { updateInlineQuestionRuleInstance(instance: $instance) { id name description version pollingInterval question { queries { query version } } operations { when actions } outputs } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "instance": { "id": "b1c0f75d-770d-432a-95f5-6f59b4239c72", "name": "unencrypted-prod-data", "description": "Data stores in production tagged critical and unencrypted", "version": "v1", "pollingInterval": "ONE_DAY", "outputs": ["alertLevel"], "operations": [ { "when": { "type": "FILTER", "version": 1, "condition": [ "AND", ["queries.unencryptedCriticalData.total", "!=", 0] ] }, "actions": [ { "type": "SET_PROPERTY", "targetProperty": "alertLevel", "targetValue": "CRITICAL" }, { "type": "CREATE_ALERT" } ] } ], "question": { "queries": [ { "query": "Find DataStore with (production=true or tag.Production=true) and classification='critical' and encrypted!=true as d return d.tag.AccountName as Account, d.displayName as UnencryptedDataStores, d._type as Type, d.encrypted as Encrypted", "version": "v1", "name": "unencryptedCriticalData" } ] } } } </pre> <p>Note that the only difference for <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">update</code> is the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">"id"</code> property<br> associated with the rule instance. You can modify all settings of a rule instance.</p> <h3 data-id="create-an-alert-rule-by-referencing-a-saved-question">Create an alert rule by referencing a saved question</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation CreateReferencedQuestionRuleInstance( $instance: CreateReferencedQuestionRuleInstanceInput! ) { createReferencedQuestionRuleInstance(instance: $instance) { id name description version pollingInterval questionId questionName operations { when actions } outputs } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "instance": { "name": "unencrypted-prod-data", "description": "Data stores in production tagged critical and unencrypted", "version": "v1", "pollingInterval": "ONE_DAY", "outputs": ["alertLevel"], "operations": [ { "when": { "type": "FILTER", "version": 1, "condition": [ "AND", ["queries.unencryptedCriticalData.total", "!=", 0] ] }, "actions": [ { "type": "SET_PROPERTY", "targetProperty": "alertLevel", "targetValue": "CRITICAL" }, { "type": "CREATE_ALERT" } ] } ], "questionId": "uuid-of-saved-question", "questionName": "name-of-saved-question" // either questionId or questionName must be specified } } </pre> <p>Note that you must specify either <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">questionName</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">questionId</code> in the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">instance</code> for creation.<br> If you specify both, they must refer to the same question. After the rule is saved,<br> subsequent requests will return both <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">questionId</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">questionName</code>.</p> <h3 data-id="update-an-alert-rule-with-a-referenced-question">Update an alert rule with a referenced question</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation UpdateReferencedQuestionRuleInstance( $instance: UpdateReferencedQuestionRuleInstanceInput! ) { updateReferencedQuestionRuleInstance(instance: $instance) { id name description version pollingInterval questionId questionName operations { when actions } outputs } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "instance": { "id": "b1c0f75d-770d-432a-95f5-6f59b4239c72", "name": "unencrypted-prod-data", "description": "Data stores in production tagged critical and unencrypted", "version": "v1", "pollingInterval": "ONE_DAY", "outputs": ["alertLevel"], "operations": [ { "when": { "type": "FILTER", "version": 1, "condition": [ "AND", ["queries.unencryptedCriticalData.total", "!=", 0] ] }, "actions": [ { "type": "SET_PROPERTY", "targetProperty": "alertLevel", "targetValue": "CRITICAL" }, { "type": "CREATE_ALERT" } ] } ], "questionId": "uuid-of-saved-question", "questionName": "name-of-saved-question" } } </pre> <p>Note that the only difference in <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">update</code> is the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">"id"</code> property<br> associated with the rule instance. You can modify any of the settings of<br> a rule instance. Updates are not required to specify <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">questionId</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">questionName</code>,<br> but you can specify either for <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">update</code>, and if you specify both they must refer to<br> the same saved question.</p> <h3 data-id="delete-an-alert-rule">Delete an alert rule</h3> <p>You can use this operation to delete any rule instance, regardless of whether it uses<br> an inline question or a referenced question.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation DeleteRuleInstance($id: ID!) { deleteRuleInstance(id: $id) { id } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "b1c0f75d-770d-432a-95f5-6f59b4239c72" } </pre> <p>Note that deleting an alert rule this way does <strong>not</strong> dismiss active alerts<br> already triggered by this rule. It is recommended that you <strong>Disable</strong> a rule in the<br> Alerts app UI instead of deleting one.</p> <h3 data-id="trigger-an-alert-rule-on-demand">Trigger an alert rule on demand</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation EvaluateRuleInstance($id: ID!) { evaluateRuleInstance(id: $id) { outputs { name value } } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "b1c0f75d-770d-432a-95f5-6f59b4239c72" } </pre> <h2 data-id="question-operations">Question Operations</h2> <p><strong>Endpoint:</strong> <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">/graphql</code></p> <h3 data-id="create-a-question">Create a Question</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation CreateQuestion($question: CreateQuestionInput!) { createQuestion(question: $question) { id title description queries { name query version resultsAre } variables { name required default } compliance { standard requirements } accountId integrationDefinitionId } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "question": { "title": "What are my production data stores and their encryption status?", "tags": ["SecOps"], "description": "Returns a list of all production entities.", "queries": [ { "name": "prod-datastores-encrypted", "query": "Find * with tag.Production=true and encrypted=true", "resultsAre": "GOOD" }, { "name": "prod-datastores-unencrypted", "query": "Find * with tag.Production=true and encrypted!=true", "resultsAre": "BAD" } ], "compliance": [ { "standard": "NIST CSF", "requirements": ["ID.AM-1"] } ] } } </pre> <p>!!! note - <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code> field is optional - <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code> is recommended to be a single word without special characters - <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">resultsAre</code> with values <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">GOOD</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">BAD</code>, and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">UNKNOWN</code> are used to<br> determine gaps/issues and to perform continuous compliance assessment.<br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">INFORMATIVE</code> is the default value.</p> <h3 data-id="update-a-question">Update a question</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation UpdateQuestion($id: ID!, $update: QuestionUpdate!) { updateQuestion(id: $id, update: $update) { id title description queries { name query version resultsAre } variables { name required default } compliance { standard requirements } accountId integrationDefinitionId } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "sj3j9f0j2ndlsj300swdjfjs", "update": { "title": "What are my production data stores and their encryption status?", "tags": ["SecOps"], "description": "Returns a list of all production entities.", "queries": [ { "name": "prod-datastores-encrypted", "query": "Find * with tag.Production=true and encrypted=true", "resultsAre": "GOOD" }, { "name": "prod-datastores-unencrypted", "query": "Find * with tag.Production=true and encrypted!=true", "resultsAre": "BAD" } ], "compliance": [ { "standard": "NIST CSF", "requirements": ["ID.AM-1"] } ] } } </pre> <p>Note that the only difference here for <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">update</code> is the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">"id"</code> property<br> associated with the question.</p> <h3 data-id="delete-a-question">Delete a question</h3> <pre class="code codeBlock" spellcheck="false" tabindex="0"> mutation DeleteQuestion($id: ID!) { deleteQuestion(id: $id) { id title description queries { query name version } variables { name required default } tags accountId integrationDefinitionId } } } </pre> <p>variables:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "slj3098s03j-i2ojd0j2-sjkkdjf" } </pre> <h2 data-id="integration-operations">Integration Operations</h2> <h3 data-id="scheduling-integration-jobs">Scheduling Integration Jobs</h3> <p>Use the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">pollingIntervalCronExpression</code> to set an <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">hour</code> or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">dayOfWeek</code> value for an integration configuration to run.</p> <h4 data-id="set-the-hour">Set the Hour</h4> <p>When using the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_DAY</code> polling interval, you can pass an optional <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">pollingIntervalCronExpression</code> to specify a time of day for the integration to execute.</p> <p>The following configuration sets an integration to execute daily between 00:00 and 01:00 UTC.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "pollingInterval": "ONE_DAY", "pollingIntervalCronExpression": { "hour": 0 } } </pre> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">pollingIntervalCronExpression.hour</code> accepts an integer between 0 and 23.</p> <h4 data-id="set-the-day-of-the-week">Set the Day of the Week</h4> <p>When using the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ONE_WEEK</code> polling interval, you can pass an optional <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">pollingIntervalCronExpression</code> to specify both a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">dayOfWeek</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">hour</code> for the integration to execute.</p> <p>The following configuration sets an integration to execute weekly on Sunday between 00:00 and 01:00 UTC.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "pollingInterval": "ONE_WEEK", "pollingIntervalCronExpression": { "hour": 0, "dayOfWeek": 0 } } </pre> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">pollingIntervalCronExpression.dayOfWeek</code> accepts an integer between 0 (Sunday) and 6 (Saturday).</p> <h4 data-id="example-mutation">Example Mutation</h4> <p>This is an example of a GraphQL mutation that updates the hour and day of the week for a specific configuration of an integration in JupiterOne:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">mutation integrationInstance( $id: String! $pollingIntervalCronExpression: IntegrationPollingIntervalCronExpressionInput ) { updateIntegrationInstance( id: $id update: { pollingIntervalCronExpression: $pollingIntervalCronExpression } ) { id name pollingInterval pollingIntervalCronExpression { hour dayOfWeek } } } </pre> <p>Variables for the mutation:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "00000000-0000-0000-0000-000000000000", "pollingIntervalCronExpression": { "hour": 0, "dayOfWeek": 0 } } </pre> <p>Variables:</p> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>: the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> of the configuration for which you want to update the hour and/or day of week. This ID is visible in each integration configuration in your account. To find the ID in your JupiterOne account, go to <strong>Settings > Integration > {integration name} > {configuration name}</strong> > value in the ID field.</p> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">hour</code>: an integer between 0 and 23 that represents the hour of the day in UTC when you want the integration to run.</p> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">dayofWeek</code>: an integer between 0 and 6 that represents the day of the week Sunday through Saturday<br> on which you want the integration to run.</p> <h4 data-id="example-query">Example Query</h4> <p>This is an example of a GraphQL query that returns the current values in the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">hour</code> and <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">dayOfWeek</code> parameters for a specific integration configuration:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query integrationInstance($id: String!) { integrationInstance(id: $id) { id name pollingInterval pollingIntervalCronExpression { hour dayOfWeek } } } </pre> <p>Variable for the query:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "00000000-0000-0000-0000-000000000000" } </pre> <p>Variables:</p> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>: the <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> of the configuration for which you want to update the hour and/or day of week. This ID is visible in each integration configuration in your account. To find the ID in your JupiterOne account go to <strong>Settings > Integration > {integration name} > {configuration name} ></strong> value in the ID field.</p> <h3 data-id="finding-an-integration-definition-based-on-a-type">Finding an Integration Definition Based on a Type</h3> <p>This query returns an Integration Definition. This query requires an Integration Type.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery($integrationType: String!) { findIntegrationDefinition(integrationType: $integrationType) { id name type title integrationType integrationClass configFields { key displayName description } } } </pre> <h3 data-id="getting-an-integration-definition-with-an-id">Getting an Integration Definition with an ID</h3> <p>This query returns a Integration Definition. This query requires an ID.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query getIntegrationDefinition($id: String) { integrationDefinition(id: $id) { id name type title } } </pre> <h3 data-id="list-integration-definitions">List Integration Definitions</h3> <p>This query returns a list of all Integration Definitions.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">query testQuery { integrationDefinitions { definitions { id name type title } pageInfo { endCursor hasNextPage } } } </pre> <h2 data-id="trigger-an-integration-job-via-api">Trigger an Integration Job via API</h2> <p>The following values are required in order to trigger an integration job via API: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">API_KEY</code> - An API Key must be configured before leveraging the JupiterOne API. Review <a rel="nofollow" href="https://jupiterone.vanillacommunities.com/kb/articles/785-creating-user-and-account-api-keys">Enable API Key Access</a> for a guide in creating a JupiterOne API Key.</p> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">ACCOUNT_ID</code> - This value is the unique ID of your JupiterOne Account, found in Settings under Account Management.</p> <p><img src="https://us.v-cdn.net/6035534/uploads/CDVC6I7IKK13/api-account-id.png" alt="API Account ID" class="embedImage-img importedEmbed-img"></img></p> <p><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">INTEGRATION_INSTANCE_ID</code> - This value is the ID of the specific integration instance that will be triggered, found in Settings under Integrations and then selecting the specific integration that has been configured (Integrations - Configurations - Settings).</p> <p><img src="https://us.v-cdn.net/6035534/uploads/XSBA0W50YJ6M/api-integration-instance-id.png" alt="API Integration Instance ID" class="embedImage-img importedEmbed-img"></img></p> <p><strong>Sample request:</strong></p> <p>Endpoint:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST <a href="https://api.us.jupiterone.io/graphql" rel="nofollow">https://api.us.jupiterone.io/graphql</a> </pre> <p>Headers:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "Content-Type": "application/json", "Accept": "application/json", "JupiterOne-Account": "{Account_ID}", "Authorization": "Bearer {API_Key}" } </pre> <p>Body:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "query": "mutation Invoke { invokeIntegrationInstance(id: INTEGRATION_INSTANCE_ID) { success } }" } </pre> <h2 data-id="retrieve-jupiterone-audit-events-via-api">Retrieve JupiterOne Audit Events via API</h2> <p>User events in your JupiterOne account are logged and can be accessed via API.</p> <p><strong>Sample request:</strong></p> <p>Endpoint:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST <a href="https://api.us.jupiterone.io/graphql" rel="nofollow">https://api.us.jupiterone.io/graphql</a> </pre> <p>Headers:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "Content-Type": "application/json", "JupiterOne-Account": "{Account_ID}", "Authorization": "Bearer {API_Key}" } </pre> <p>Body:</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "query": "Query($limit: Int, $cursor: String) { getAuditEventsForAccount(limit: $limit, cursor: $cursor) { items { id resourceType resourceId category timestamp performedByUserId data } pageInfo { endCursor hasNextPage } }" } </pre> <h2 data-id="additional-api-examples">Additional API Examples</h2> <p><strong>Creating entities and a relationship between them</strong></p> <p><strong>Note:</strong><br> The following mutations utilize a J1Client.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">const CREATE_ENTITY = gql` mutation createEntity ( $entityKey: String! $entityType: String! $entityClass: String! $timestamp: Long $properties: JSON ) { createEntity( entityKey: $entityKey entityType: $entityType entityClass: $entityClass properties: $properties ) { . . . }`; const CREATE_RELATIONSHIP = gql` mutation CreateRelationship ( $relationshipKey: String! $relationshipType: String! $relationshipClass: String! $fromEntityId: String! $toEntityId: String! ) { createRelationship ( relationshipKey: $relationshipKey relationshipType: $relationshipType relationshipClass: $relationshipClass fromEntityId: $fromEntityId toEntityId: $toEntityId ) { . . . }`; const entity1 = await j1Client.mutate({ mutation: CREATE_ENTITY, variable: { entityKey: 'Example Key', entityType: 'ExampleType', entityClass: 'ExampleClass', properties: { 'tag.key': 'tagvalue' } } }); const entity2 = await j1Client.mutate({ mutation CREATE_ENTITY, variable: { entityKey: 'Other Example Key', entityType: 'OtherType', entityClass: 'OtherClass', properties: { 'tag.key': 'tag' } } }); const relationship = await j1Client.mutate({ mutation: CREATE_RELATIONSHIP, variable: { relationshipKey: entity1._key + ' |uses| ' + entity2._key, relationshipClass: 'entity_uses_entity', relationshipType: 'USES', toEntityId: entity2._id, toEntityKey: entity1._id, } }); </pre> <h2 data-id="iam-operations-beta">IAM Operations (beta)</h2> <p><strong>Note:</strong><br> The IAM API is in beta and only works for accounts configured with SSO. Email support@jupiterone.com to enable access to these APIs because we will need to verify your company's domain name.</p> <p><strong>Note:</strong><br><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessAdmin</code> permission is required for all IAM operations.</p> <p><strong>Endpoint:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">POST <a href="https://api.us.jupiterone.io/iam/graphql" rel="nofollow">https://api.us.jupiterone.io/iam/graphql</a> </pre> <p><strong>Headers:</strong></p> <pre class="code codeBlock" spellcheck="false" tabindex="0">Content-Type: application/json Accept: application/json JupiterOne-Account: {Account_ID} Authorization: Bearer {API_Key} </pre> <h3 data-id="get-iam-groups">Get IAM groups</h3> <p><strong>Query: iamGroups</strong></p> <p>Retrieves all account <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">groups</code> within the query limit.</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">limit</code>: (required) max number of records to return</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">cursor</code>: (optional) continuation token</li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">query Query($limit: Int!, $cursor: String) { iamGroups(limit: $limit, cursor: $cursor) { items { id name description } pageInfo { endCursor hasNextPage } } } </pre> <p><strong>API Samples</strong></p> <p>Sample (S1): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">iamGroups</code></p> <p>(S1): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "limit": 5 } </pre> <p>(S1): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "iamGroups": { "items": [ { "id": "12c2d370-89ef-4280-970b-d520ca1837be", "name": "Users", "description": "" }, { "id": "dd354c7a-1b9b-4579-ac5e-873fe3b2c851", "name": "Administrators", "description": "Admin users" } ], "pageInfo": { "endCursor": "eyJhY2NvdW50I...", "hasNextPage": true } } } } </pre> <h3 data-id="get-users-of-iam-group">Get Users of IAM group</h3> <p><strong>Query: iamGroupUsers</strong></p> <p>Retrieves all group members of the specified <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">group</code> (by <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>) within the query limit.</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">groupId</code>: (required) unique group identifier</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">limit</code>: (required) max number of records to return</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">cursor</code>: (optional) continuation token</li> </ul><blockquote class="UserQuote blockquote"><div class="QuoteText blockquote-content"> <p class="blockquote-line">Note: The item.<code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code> property in the response is the JupiterOne <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">uid</code>.</p> </div></blockquote> <pre class="code codeBlock" spellcheck="false" tabindex="0">query Query($groupId: String!, $limit: Int!, $cursor: String) { iamGroupUsers(groupId: $groupId, limit: $limit, cursor: $cursor) { items { id email } pageInfo { endCursor hasNextPage } } } </pre> <p><strong>API Samples</strong></p> <p>Sample (S1): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">iamGroupUsers</code></p> <p>(S1): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "groupId": "22c2d370-89ef-4280-970b-d520ca1837be", "limit": 5 } </pre> <p>(S1): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "iamGroupUsers": { "items": [ { "id": "222xxx222_abc", "email": "abc@mycompany.com" }, { "id": "222xxx222_def@mycompany.com", "email": "def@mycompany.com" } ], "pageInfo": { "endCursor": "eyJ1c2VyIjoiaj...", "hasNextPage": true } } } } </pre> <h3 data-id="add-iam-user-to-group">Add IAM User to Group</h3> <p><strong>Mutation: addIamUserToGroupByEmail</strong></p> <p>Adds a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">user</code> to a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">group</code> using the specified email and group ID.</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">groupId</code>: (required)</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">userEmail</code>: (required)</li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">mutation Mutation($groupId: String!, $userEmail: String!) { addIamUserToGroupByEmail(groupId: $groupId, userEmail: $userEmail) { success } } </pre> <p><strong>API Samples</strong></p> <p>Sample (S1): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">addIamUserToGroupByEmail</code></p> <p>(S1): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "groupId": "22c2d370-89ef-4280-970b-d520ca1837be", "userEmail": "abc@mycompany.com" } </pre> <p>(S1): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "addIamUserToGroupByEmail": { "success": true } } } </pre> <h3 data-id="remove-iam-user-from-group">Remove IAM user from group</h3> <p><strong>Mutation: removeIamUserFromGroupByEmail</strong></p> <p>Removes a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">user</code> from a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">group</code> using the specified email and group ID.</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">groupId</code>: (required)</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">userEmail</code>: (required)</li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">mutation Mutation($groupId: String!, $userEmail: String!) { removeIamUserFromGroupByEmail(groupId: $groupId, userEmail: $userEmail) { success } } </pre> <p><strong>API Samples</strong></p> <p>Sample (S1): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">removeIamUserFromGroupByEmail</code></p> <p>(S1): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "groupId": "22c2d370-89ef-4280-970b-d520ca1837be", "userEmail": "xyz@mycompany.com" } </pre> <p>(S1): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "removeIamUserFromGroupByEmail": { "success": true } } } </pre> <h3 data-id="create-iam-group">Create IAM Group</h3> <p><strong>Mutation: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">createIamGroup</code></strong></p> <p>Creates a new <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">group</code> with a specified <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code> and optionally: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">description</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryPolicy</code>, and/or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">abacPermissions</code>.</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code>: (required) must be unique to all other groups.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">description</code>: (optional)</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">abacPermissions</code>: (optional)</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryPolicy</code>: (optional)</li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">mutation Mutation( $name: String! $description: String $abacPermissions: [String!] $queryPolicy: [JSON!] ) { createIamGroup( name: $name description: $description abacPermissions: $abacPermissions queryPolicy: $queryPolicy ) { id name description } } </pre> <p><strong>API Type Definitions</strong></p> <p><strong>queryPolicy</strong></p> <p>Description: Group Query Policies define query access for members of a particular group. Setting this property via the IAM API will <strong>overwrite</strong> any existing queryPolicy for the given group. If updating this property, <em>always</em> define the full <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryPolicy</code> to enforce.</p> <p>Type: list of <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> objects with primitive values or an array or primitive values.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">type queryPolicy = [JSON!]; type JSON = { [key: string]: string | number | boolean || (string | number | boolean)[]; } </pre> <p><strong>abacPermissions</strong></p> <p>Description: ABAC permissions define application access for members of a perticular group. Setting this property via the IAM API will <strong>overwrite</strong> any existing permissions for the given group. If updating this property, <em>always</em> define the full list of <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">permissions</code> that should be granted.</p> <p>Type: list of valid <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">permission</code> strings (see table below).</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">type abacPermissions = [permission!] type permission = string // must be a valid permission string </pre> <p><strong>Permission Strings: READ-ONLY</strong></p> <table><thead><tr><th align="left">DISPLAY NAME (J1 APP)</th> <th align="center">ACCESS</th> <th align="right">PERMISSION</th> </tr></thead><tbody><tr><td align="left"><em>All Apps And Resources</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">fullReadAccess</code></td> </tr><tr><td align="left"><em>Shared: Questions</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">readQuestions</code></td> </tr><tr><td align="left"><em>GraphData</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">readGraph</code></td> </tr><tr><td align="left"><em>Landing</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessLanding</code></td> </tr><tr><td align="left"><em>Assets</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessAssets</code></td> </tr><tr><td align="left"><em>Policies</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessPolicies</code></td> </tr><tr><td align="left"><em>Compliance</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessCompliance</code></td> </tr><tr><td align="left"><em>Alerts</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessRules</code></td> </tr><tr><td align="left"><em>GraphViewer</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessGalaxy</code></td> </tr><tr><td align="left"><em>Insights</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessInsights</code></td> </tr><tr><td align="left"><em>Integrations</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessIntegrations</code></td> </tr><tr><td align="left"><em>Endpoint Compliance</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessEndpointCompliance</code></td> </tr></tbody></table><p><strong>Permission Strings: ADMIN</strong></p> <table><thead><tr><th align="left">DISPLAY NAME (J1 APP)</th> <th align="center">ACCESS</th> <th align="right">PERMISSION</th> </tr></thead><tbody><tr><td align="left"><em>All Apps And Resources</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessAdmin</code></td> </tr><tr><td align="left"><em>Shared: Questions</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">writeQuestions</code></td> </tr><tr><td align="left"><em>GraphData</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">writeGraph</code></td> </tr><tr><td align="left"><em>Landing</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminLanding</code></td> </tr><tr><td align="left"><em>Assets</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminAssets</code></td> </tr><tr><td align="left"><em>Policies</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminPolicies</code></td> </tr><tr><td align="left"><em>Compliance</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminCompliance</code></td> </tr><tr><td align="left"><em>Alerts</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminRules</code></td> </tr><tr><td align="left"><em>GraphViewer</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminGalaxy</code></td> </tr><tr><td align="left"><em>Insights</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminInsights</code></td> </tr><tr><td align="left"><em>Integrations</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminIntegrations</code></td> </tr><tr><td align="left"><em>Endpoint Compliance</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminEndpointCompliance</code></td> </tr><tr><td align="left"><em>ENABLE API KEY ACCESS</em></td> <td align="center">*</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">apiKeyUser</code></td> </tr></tbody></table><p><strong>API Samples</strong></p> <p>Sample (S1): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">createIamGroup</code></p> <p>(S1): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "Users" } </pre> <p>(S1): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "createIamGroup": { "id": "90909-11ef-4280-970b-4444ca1837be", "name": "Users" } } } </pre> <p>Sample (S2): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">createIamGroup</code></p> <p>(S2): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "UsersX", "description": "A group for X users" } </pre> <p>(S2): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "createIamGroup": { "id": "11c2d370-89ef-4280-970b-d520ca1837be", "name": "UsersX", "description": "A group for X users" } } } </pre> <p>Sample (S3): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">createIamGroup</code></p> <p>(S3): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "Support", "description": "A group for support users", "queryPolicy": [ { "_type": ["aws_ecr_image", "bitbucket_pullrequest"] } ] } </pre> <p>(S3): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "createIamGroup": { "id": "23434-454-45656-65656-4564564565", "name": "Support", "description": "A group for support users" } } } </pre> <p>Sample (S4): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">createIamGroup</code></p> <p>(S4): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "name": "Admins", "queryPolicy": [ { "_type": "aws_ecs_task_definition", "_class": "Account" }, { "_type": "aws_ecr_image" } ] } </pre> <p>(S4): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "createIamGroup": { "id": "87787-6787-678678-778-6786786", "name": "Admins" } } } </pre> <h3 data-id="update-iam-group">Update IAM Group</h3> <p><strong>Mutation: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">updateIamGroup</code></strong></p> <p>Updates a <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">group</code>'s properties: <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">description</code>, <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryPolicy</code>, and/or <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">abacPermissions</code>.</p> <ul><li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">id</code>: (required) must tie to an existing group.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">name</code>: (optional) must be unique to all other groups.</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">description</code>: (optional)</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">abacPermissions</code>: (optional)</li> <li><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryPolicy</code>: (optional)</li> </ul><pre class="code codeBlock" spellcheck="false" tabindex="0">mutation Mutation( $id: String! $name: String $description: String $abacPermissions: [String!] $queryPolicy: [JSON!] ) { updateIamGroup( id: $id name: $name description: $description abacPermissions: $abacPermissions queryPolicy: $queryPolicy ) { id name description } } </pre> <p><strong>API Type Definitions</strong></p> <p><strong>queryPolicy</strong></p> <p>Description: Group Query Policies define query access for members of a particular group. Setting this property via the IAM API will <strong>overwrite</strong> any existing queryPolicy for the given group. If updating this property, <em>always</em> define the full <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">queryPolicy</code> to enforce.</p> <p>Type: list of <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">JSON</code> objects with primitive values or an array or primitive values.</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">type queryPolicy = [JSON!]; type JSON = { [key: string]: string | number | boolean || (string | number | boolean)[]; } </pre> <p><strong>abacPermissions</strong></p> <p>Description: ABAC permissions define application access for members of a perticular group. Setting this property via the IAM API will <strong>overwrite</strong> any existing permissions for the given group. If updating this property, <em>always</em> define the full list of <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">permissions</code> that should be granted.</p> <p>Type: list of valid <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">permission</code> strings (see table below).</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">type abacPermissions = [permission!]; type permission = string; // must be a valid permission string </pre> <p><strong>Permission Strings: READ-ONLY</strong></p> <table><thead><tr><th align="left">DISPLAY NAME (J1 APP)</th> <th align="center">ACCESS</th> <th align="right">PERMISSION</th> </tr></thead><tbody><tr><td align="left"><em>All Apps And Resources</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">fullReadAccess</code></td> </tr><tr><td align="left"><em>Shared: Questions</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">readQuestions</code></td> </tr><tr><td align="left"><em>GraphData</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">readGraph</code></td> </tr><tr><td align="left"><em>Landing</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessLanding</code></td> </tr><tr><td align="left"><em>Assets</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessAssets</code></td> </tr><tr><td align="left"><em>Policies</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessPolicies</code></td> </tr><tr><td align="left"><em>Compliance</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessCompliance</code></td> </tr><tr><td align="left"><em>Alerts</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessRules</code></td> </tr><tr><td align="left"><em>GraphViewer</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessGalaxy</code></td> </tr><tr><td align="left"><em>Insights</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessInsights</code></td> </tr><tr><td align="left"><em>Integrations</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessIntegrations</code></td> </tr><tr><td align="left"><em>Endpoint Compliance</em></td> <td align="center">READ</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessEndpointCompliance</code></td> </tr></tbody></table><p><strong>Permission Strings: ADMIN</strong></p> <table><thead><tr><th align="left">DISPLAY NAME (J1 APP)</th> <th align="center">ACCESS</th> <th align="right">PERMISSION</th> </tr></thead><tbody><tr><td align="left"><em>All Apps And Resources</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">accessAdmin</code></td> </tr><tr><td align="left"><em>Shared: Questions</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">writeQuestions</code></td> </tr><tr><td align="left"><em>GraphData</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">writeGraph</code></td> </tr><tr><td align="left"><em>Landing</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminLanding</code></td> </tr><tr><td align="left"><em>Assets</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminAssets</code></td> </tr><tr><td align="left"><em>Policies</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminPolicies</code></td> </tr><tr><td align="left"><em>Compliance</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminCompliance</code></td> </tr><tr><td align="left"><em>Alerts</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminRules</code></td> </tr><tr><td align="left"><em>GraphViewer</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminGalaxy</code></td> </tr><tr><td align="left"><em>Insights</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminInsights</code></td> </tr><tr><td align="left"><em>Integrations</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminIntegrations</code></td> </tr><tr><td align="left"><em>Endpoint Compliance</em></td> <td align="center">ADMIN</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">adminEndpointCompliance</code></td> </tr><tr><td align="left"><em>ENABLED API KEY ACCESS</em></td> <td align="center">*</td> <td align="right"><code class="code codeInline code codeInline" spellcheck="false" tabindex="0">apiKeyUser</code></td> </tr></tbody></table><p><strong>API Samples</strong></p> <p>Sample (S1): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">updateIamGroup</code></p> <p>(S1): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "90909-11ef-4280-970b-4444ca1837be", "name": "Users" } </pre> <p>(S1): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "updateIamGroup": { "id": "90909-11ef-4280-970b-4444ca1837be", "name": "Users", "description": "original description.." } } } </pre> <p>Sample (S2): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">updateIamGroup</code></p> <p>(S2): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "90909-11ef-4280-970b-4444ca", "name": "UsersX", "description": "A group for X users" } </pre> <p>(S2): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "updateIamGroup": { "id": "90909-11ef-4280-970b-4444ca", "name": "UsersX", "description": "A group for X users" } } } </pre> <p>Sample (S3): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">updateIamGroup</code></p> <p>(S3): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "90909-11ef-4280-970b-4444ca", "abacPermissions": ["accessPolicies", "writeQuestions", "accessGalaxy"], "queryPolicy": [ { "_type": "aws_ecs_task_definition" } ] } </pre> <p>(S3): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "updateIamGroup": { "id": "90909-11ef-4280-970b-4444ca", "name": "UsersX", "description": "A group for X users" } } } </pre> <p>Sample (S4): <code class="code codeInline code codeInline" spellcheck="false" tabindex="0">updateIamGroup</code></p> <p>(S4): Request</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "id": "90909-11ef-4280-970b-4444ca", "description": "allow account class", "queryPolicy": [ { "_type": "aws_ecs_task_definition", "_class": "Account" }, { "_integrationType": ["whitehat"] } ] } </pre> <p>(S4): Response</p> <pre class="code codeBlock" spellcheck="false" tabindex="0">{ "data": { "updateIamGroup": { "id": "90909-11ef-4280-970b-4444ca", "name": "UsersX", "description": "allow account class" } } } </pre> </article> </main>