Ticket Providers

Let users create support tickets directly from the chat widget. Kody supports five ticket providers out of the box.

Enable tickets in your site config by setting tickets.enabled to true and adding at least one provider to the tickets.providers array. When multiple providers are configured, tickets are sent to all of them simultaneously.

You can configure which fields are required from the user via tickets.requiredFields. Valid values are: "name", "email", "subject", and "description". Defaults to ["email", "description"].

Jira

Creates issues in your Jira Cloud instance. Uses the Jira REST API v3 with email + API token authentication.

FieldTypeDefaultDescription
providerliteralMust be "jira".
baseUrlstring (URL)requiredYour Jira instance URL (e.g. https://yourorg.atlassian.net).
projectKeystringrequiredJira project key (e.g. SUP, HELP, SUPPORT). Min 1 char.
apiTokenstringrequiredJira API token for authentication. Min 1 char.
emailstring (email)requiredAtlassian account email associated with the API token.
issueTypestring"Task"Issue type to create (e.g. "Task", "Bug", "Story"). Must match an issue type in your project.

Getting an API token:

  1. Go to Atlassian API Tokens
  2. Click "Create API token" and give it a descriptive label
  3. Copy the token and use it as the apiToken value
  4. Use the email address of your Atlassian account as the email value
{
  "provider": "jira",
  "baseUrl": "https://yourorg.atlassian.net",
  "projectKey": "SUP",
  "apiToken": "your-api-token",
  "email": "you@example.com",
  "issueType": "Task"
}

GitHub Issues

Creates issues in a GitHub repository. Uses the GitHub REST API with a personal access token. You can auto-apply labels to organize tickets.

FieldTypeDefaultDescription
providerliteralMust be "github".
ownerstringrequiredGitHub organization or user that owns the repository.
repostringrequiredRepository name where issues will be created.
tokenstringrequiredPersonal access token with Issues write permission.
labelsstring[]["kody-ticket"]Labels to apply to created issues. The labels must exist in the repository.

Creating a personal access token:

  1. Go to GitHub Fine-grained tokens
  2. Click "Generate new token"
  3. Select the target repository and grant Issues: Read and write permission
  4. Copy the token and use it as the token value
{
  "provider": "github",
  "owner": "your-org",
  "repo": "support",
  "token": "ghp_xxxxxxxxxxxx",
  "labels": ["kody-ticket", "bug"]
}

Linear

Creates issues in a Linear team using the Linear GraphQL API. Issues are assigned to the specified team and can have labels applied automatically.

FieldTypeDefaultDescription
providerliteralMust be "linear".
apiKeystringrequiredLinear API key. Min 1 char.
teamIdstringrequiredTeam ID to create issues in. You can find this in your team settings or via the Linear API.
labelIdsstring[][]Label IDs to apply to created issues.

Getting an API key:

  1. Go to Linear Settings → API
  2. Create a new personal API key
  3. Copy the key and use it as the apiKey value
{
  "provider": "linear",
  "apiKey": "lin_api_xxxxxxxxxxxx",
  "teamId": "TEAM-ID",
  "labelIds": ["label-id-1"]
}

Email

Note: The email provider is currently a stub implementation. SMTP delivery is not yet functional, but the configuration schema is stable and will be preserved when the implementation ships.

Sends ticket notifications via email using SMTP. The recipient address is required; all SMTP fields are optional to support future hosted email relay.

FieldTypeDefaultDescription
providerliteralMust be "email".
tostring (email)requiredRecipient email address. Must be a valid email.
fromstring (email)Sender email address. Must be a valid email. Optional.
smtpHoststringSMTP server hostname (e.g. smtp.gmail.com). Optional.
smtpPortintegerSMTP server port (e.g. 587 for TLS, 465 for SSL). Optional.
smtpUserstringSMTP username for authentication. Optional.
smtpPassstringSMTP password for authentication. Stored server-side only. Optional.
{
  "provider": "email",
  "to": "support@example.com",
  "from": "noreply@example.com",
  "smtpHost": "smtp.example.com",
  "smtpPort": 587,
  "smtpUser": "smtp-user",
  "smtpPass": "smtp-password"
}

Webhook

Sends ticket data to any HTTP endpoint. This is the most flexible option — use it to integrate with Slack, Discord, Notion, your own API, or any service that accepts webhooks.

FieldTypeDefaultDescription
providerliteralMust be "webhook".
urlstring (URL)requiredWebhook endpoint URL. Must be a valid URL.
methodenum"POST"HTTP method: "POST" or "PUT".
headersRecord<string, string>{}Custom headers to include in the request. Useful for authentication tokens or content type overrides.
secretstringHMAC-SHA256 secret for signature verification. When set, Kody includes an X-Kody-Signature header. Optional.

Signature Verification

When a secret is configured, Kody includes an X-Kody-Signature header containing an HMAC-SHA256 hex digest of the request body. Verify this on your server to ensure requests are authentic and have not been tampered with.

{
  "provider": "webhook",
  "url": "https://example.com/api/tickets",
  "method": "POST",
  "headers": {
    "Authorization": "Bearer your-token"
  },
  "secret": "your-hmac-secret"
}
Verifying the signature (Node.js):
import crypto from "node:crypto";

function verify(body: string, signature: string, secret: string) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected),
  );
}

Using Multiple Providers

You can configure multiple providers simultaneously. Tickets are sent to all of them when a user submits one. This is useful for keeping multiple systems in sync, e.g. creating a GitHub issue and sending a Slack notification via webhook at the same time:

{
  "tickets": {
    "enabled": true,
    "promptMessage": "Would you like me to create a support ticket?",
    "providers": [
      {
        "provider": "github",
        "owner": "your-org",
        "repo": "support",
        "token": "ghp_...",
        "labels": ["kody-ticket"]
      },
      {
        "provider": "webhook",
        "url": "https://hooks.slack.com/services/T.../B.../xxx",
        "method": "POST"
      }
    ],
    "requiredFields": ["name", "email", "description"]
  }
}