Integrations API

HTTP reference for Jira, GitHub and Slack connections — create, test, sync, inbound callbacks and ticket links.

All paths are relative to https://api.aleex-rank.ai/api/v2 and authenticate with X-API-Key: rk_... (see REST API). The supported providers are jira, github and slack only. This is not the Rank support-desk Tickets API, which talks to Rank’s own Jira.

Create integrations before you launch pentests. There is no backfill of findings that already exist — call POST …/sync if you need to push the current inventory. Findings whose validation_status is failed never open tickets.

Providers and limits

GET /integrations/providers
{
  "success": true,
  "data": {
    "providers": [
      {
        "provider": "jira",
        "label": "Jira Cloud",
        "auth_type": "basic",
        "credential_fields": ["email", "api_token"],
        "required_config": ["project_key"],
        "optional_config": ["issue_type", "labels", "closed_transition", "reopen_transition"],
        "secret_config": ["inbound_secret"],
        "supports_inbound": true,
        "tracks_issue_state": true
      },
      {
        "provider": "github",
        "label": "GitHub Issues",
        "credential_fields": ["token"],
        "required_config": ["owner", "repo"],
        "supports_inbound": true
      },
      {
        "provider": "slack",
        "label": "Slack",
        "credential_fields": ["bot_token"],
        "required_config": ["channel"],
        "supports_inbound": false
      }
    ]
  }
}

How many connections you may hold depends on tier (see Teams & tiers):

CasualProUltraBusinessEnterprise
none2515unlimited

List and create

GET  /integrations
POST /integrations
FieldTypeRequiredNotes
providerstringYesjira, github or slack
namestringYesDisplay name
credentialsobjectYesProvider-specific; never returned on later GETs
configobjectYesProvider-specific
eventsstring[]NoOutbound Rank events to push
field_mappingsobjectNopriority, validation_labels, escalate_on_kev, epss_escalation_threshold
base_urlstringConditionalJira site URL
sync_inboundboolNoReceive ticket-close callbacks; invalid on Slack
team_idintConditionalRequired when the connection belongs to a team
activeboolNoDefault true
{
  "provider": "jira",
  "name": "Acme Jira",
  "credentials": {"email": "bot@acme.example", "api_token": "ATATT3x..."},
  "config": {
    "project_key": "SEC",
    "issue_type": "Bug",
    "labels": ["rank", "pentest"],
    "closed_transition": "Done",
    "reopen_transition": "To Do",
    "inbound_secret": "a-long-random-secret"
  },
  "events": ["vulnerability.created", "vulnerability.resolved", "vulnerability.reopened"],
  "field_mappings": {
    "priority": {"critical": "Highest", "high": "High", "medium": "Medium", "low": "Low", "info": "Lowest"},
    "escalate_on_kev": true
  },
  "base_url": "https://acme.atlassian.net",
  "sync_inbound": true,
  "team_id": 4,
  "active": true
}
{
  "success": true,
  "data": {
    "message": "Integration created",
    "integration": {
      "id": 21,
      "provider": "jira",
      "name": "Acme Jira",
      "config": {"project_key": "SEC", "issue_type": "Bug"},
      "events": ["vulnerability.created", "vulnerability.resolved", "vulnerability.reopened"],
      "sync_inbound": true,
      "team_id": 4,
      "active": true,
      "has_credentials": true,
      "created_at": "2026-03-02 09:00:00"
    },
    "credentials_notice": "Credentials and the inbound callback secret are stored encrypted and are never returned."
  }
}

GET /integrations returns {integrations, total} (not a paginated items envelope). Credentials, config, field mappings and callback URL stay on GET /integrations/{id}.

Retrieve, update, delete

GET    /integrations/{id}
PUT    /integrations/{id}
DELETE /integrations/{id}

PUT accepts the same fields as create (omit provider). DELETE is rejected while any linked ticket is closed_pending_retest, unless you pass ?discard_pending_retests=true.

{
  "success": false,
  "error": {
    "message": "Integration has tickets in closed_pending_retest; pass discard_pending_retests=true to delete",
    "code": 409
  }
}

Provider config

Jira

credentials: email + api_token. config.project_key is required. If sync_inbound is true, config.inbound_secret is required. Optional: issue_type, labels, closed_transition, reopen_transition. base_url is the Jira Cloud site.

GitHub

credentials: token. config requires owner and repo.

{
  "provider": "github",
  "name": "Acme GitHub",
  "credentials": {"token": "ghp_..."},
  "config": {"owner": "acme", "repo": "app"},
  "events": ["vulnerability.created", "vulnerability.resolved"],
  "sync_inbound": true
}

Slack

credentials: bot_token. config.channel is the destination (name or id). Slack has no inbound. sync_inbound: true on Slack is 400.

{
  "provider": "slack",
  "name": "SOC Slack",
  "credentials": {"bot_token": "xoxb-..."},
  "config": {"channel": "#security-findings"},
  "events": ["vulnerability.created", "vulnerability.resolved"],
  "sync_inbound": false
}
{
  "success": false,
  "error": {
    "message": "Slack does not support inbound sync",
    "code": 400
  }
}
POST /integrations/{id}/test
POST /integrations/{id}/sync
GET  /integrations/{id}/links

test checks credentials against the provider. sync pushes current eligible findings (skipped if validation_status is failed). links lists the tickets/issues/messages already opened.

{
  "success": true,
  "data": {"ok": true, "provider": "jira", "latency_ms": 180}
}
{
  "success": true,
  "data": {"created": 3, "updated": 11, "skipped": 2}
}
{
  "success": true,
  "data": {
    "items": [
      {
        "vulnerability_id": 42,
        "external_id": "SEC-1041",
        "url": "https://acme.atlassian.net/browse/SEC-1041",
        "state": "open"
      }
    ]
  }
}

Inbound callback

POST /integrations/{id}/callback/{token}

Jira and GitHub post here when a linked ticket changes. Closing a ticket marks the finding resolved and queues a retest (see Retest, auto_retest_on_ticket_close).

Verify Jira deliveries with HMAC headers X-Rank-Timestamp and X-Rank-Signature. Verify GitHub with X-Hub-Signature-256. Slack never calls this URL.

Where to go next