Connectors

Connectors parse raw HTTP requests into structured actions. Each connector knows the API schema for a specific service and maps HTTP method + URL path to an action type like github.pr.merge or stripe.charge.create.


Built-in connectors

GitHub

| Field | Value | |---|---| | Domains | api.github.com | | Actions | 20+ (PRs, issues, branches, releases, files, repos, orgs, teams) | | Auth | Authorization: token {PAT} | | GitHub Enterprise | Supported — set custom base URL in connector config |

Action types

| Action | HTTP | Risk | |---|---|---| | github.pr.create | POST /repos/{owner}/{repo}/pulls | low | | github.pr.merge | PUT /repos/{owner}/{repo}/pulls/{number}/merge | medium | | github.pr.update | PATCH /repos/{owner}/{repo}/pulls/{number} | low | | github.pr.close | PATCH /repos/{owner}/{repo}/pulls/{number} (state=closed) | low | | github.pr.review | POST /repos/{owner}/{repo}/pulls/{number}/reviews | low | | github.issue.create | POST /repos/{owner}/{repo}/issues | low | | github.issue.update | PATCH /repos/{owner}/{repo}/issues/{number} | low | | github.issue.close | PATCH /repos/{owner}/{repo}/issues/{number} (state=closed) | low | | github.branch.create | POST /repos/{owner}/{repo}/git/refs | low | | github.branch.delete | DELETE /repos/{owner}/{repo}/git/refs/{ref} | high | | github.release.create | POST /repos/{owner}/{repo}/releases | medium | | github.release.delete | DELETE /repos/{owner}/{repo}/releases/{id} | high | | github.file.create | PUT /repos/{owner}/{repo}/contents/{path} (new) | low | | github.file.update | PUT /repos/{owner}/{repo}/contents/{path} (existing) | low | | github.file.delete | DELETE /repos/{owner}/{repo}/contents/{path} | medium | | github.repo.create | POST /user/repos or POST /orgs/{org}/repos | medium | | github.repo.delete | DELETE /repos/{owner}/{repo} | high | | github.repo.update | PATCH /repos/{owner}/{repo} | low | | github.org.update | PATCH /orgs/{org} | medium | | github.team.create | POST /orgs/{org}/teams | low |

GitHub Enterprise Server (GHE)

To use with GitHub Enterprise, set a custom base URL when adding the connector:

npx tf connector add github \
  --token-env GITHUB_TOKEN \
  --base-url https://github.yourcompany.com/api/v3

The connector automatically adjusts URL parsing for the custom base URL. All action types work the same as with api.github.com.


OpenAI / Anthropic

| Field | Value | |---|---| | Domains | api.openai.com, api.anthropic.com | | Actions | 24+ (chat, embeddings, images, audio, files, fine-tuning, models) | | Auth | Authorization: Bearer {key} (OpenAI), x-api-key: {key} (Anthropic) | | Azure OpenAI | Not yet supported — use the generic connector with Azure endpoints |

Action types (OpenAI)

| Action | HTTP | Risk | |---|---|---| | openai.chat.create | POST /v1/chat/completions | low | | openai.chat.create_stream | POST /v1/chat/completions (stream=true) | low | | openai.embedding.create | POST /v1/embeddings | low | | openai.image.generate | POST /v1/images/generations | medium | | openai.image.edit | POST /v1/images/edits | medium | | openai.audio.transcribe | POST /v1/audio/transcriptions | low | | openai.audio.translate | POST /v1/audio/translations | low | | openai.audio.speech | POST /v1/audio/speech | low | | openai.file.upload | POST /v1/files | medium | | openai.file.delete | DELETE /v1/files/{id} | medium | | openai.file.list | GET /v1/files | low | | openai.finetune.create | POST /v1/fine_tuning/jobs | high | | openai.finetune.cancel | POST /v1/fine_tuning/jobs/{id}/cancel | medium | | openai.model.list | GET /v1/models | low | | openai.model.delete | DELETE /v1/models/{id} | high |

Azure OpenAI workaround

Azure OpenAI uses different endpoints ({resource}.openai.azure.com). Use the generic connector:

npx tf connector add generic \
  --domains "myresource.openai.azure.com" \
  --token-env AZURE_OPENAI_KEY \
  --auth-header "api-key"

Actions will be parsed as generic.post, generic.get, etc. For richer action types, a dedicated Azure OpenAI connector is planned.


Stripe

| Field | Value | |---|---| | Domains | api.stripe.com | | Actions | 40+ (charges, refunds, payments, subscriptions, invoices, customers, transfers) | | Auth | Authorization: Bearer {secret_key} |

Action types (selection)

| Action | HTTP | Risk | |---|---|---| | stripe.charge.create | POST /v1/charges | high | | stripe.charge.refund | POST /v1/refunds | high | | stripe.customer.create | POST /v1/customers | low | | stripe.customer.delete | DELETE /v1/customers/{id} | medium | | stripe.subscription.create | POST /v1/subscriptions | medium | | stripe.subscription.cancel | DELETE /v1/subscriptions/{id} | medium | | stripe.invoice.create | POST /v1/invoices | medium | | stripe.invoice.pay | POST /v1/invoices/{id}/pay | high | | stripe.transfer.create | POST /v1/transfers | high | | stripe.payout.create | POST /v1/payouts | high | | stripe.balance.retrieve | GET /v1/balance | low |


Slack

| Field | Value | |---|---| | Domains | slack.com, api.slack.com | | Actions | 35+ (messages, channels, files, users, admin, reactions) | | Auth | Authorization: Bearer {bot_token} |

Action types (selection)

| Action | HTTP | Risk | |---|---|---| | slack.message.post | POST /api/chat.postMessage | low | | slack.message.update | POST /api/chat.update | low | | slack.message.delete | POST /api/chat.delete | medium | | slack.channel.create | POST /api/conversations.create | medium | | slack.channel.archive | POST /api/conversations.archive | medium | | slack.channel.invite | POST /api/conversations.invite | low | | slack.file.upload | POST /api/files.upload | medium | | slack.file.delete | POST /api/files.delete | medium | | slack.user.list | GET /api/users.list | low | | slack.admin.invite | POST /api/admin.users.invite | high |


Generic HTTP

The generic connector works with any HTTP API. It parses actions based on HTTP method only.

| Field | Value | |---|---| | Domains | Any (configured per-connector) | | Actions | Method-based: generic.get, generic.post, generic.put, generic.patch, generic.delete | | Auth | Configurable header (default: Authorization: Bearer {token}) |

Adding a generic connector

# Single domain
npx tf connector add generic --domains api.example.com --token-env EXAMPLE_KEY
 
# Multiple domains
npx tf connector add generic \
  --domains "api.example.com,api.other.com" \
  --token-env EXAMPLE_KEY
 
# Custom auth header
npx tf connector add generic \
  --domains api.example.com \
  --token-env EXAMPLE_KEY \
  --auth-header "X-API-Key"

Action counting

Each HTTP request through the generic connector counts as one action, regardless of the response. This is the same as structured connectors — one request = one action.

Semantic limitations

The generic connector cannot parse domain-specific action types. A POST to any endpoint is generic.post. For richer action types and risk hints, use a structured connector or build a custom one.


Custom connector development

You can build custom connectors in Go to add domain-specific action parsing for APIs that don't have a built-in connector.

Connector interface

Every connector implements this Go interface:

// internal/connectors/interface.go
type Connector interface {
    // Name returns the connector identifier (e.g., "github", "stripe")
    Name() string
 
    // Domains returns the list of domains this connector handles
    Domains() []string
 
    // ParseAction parses an HTTP request into a structured action
    ParseAction(req *http.Request) (*Action, error)
 
    // InjectCredentials adds authentication to the outbound request
    InjectCredentials(req *http.Request, cred *Credential) error
}
 
type Action struct {
    Type        string            // e.g., "github.pr.merge"
    Resource    Resource
    Parameters  map[string]any
    RiskHints   map[string]any
}

Example: Custom Jira connector

package jira
 
import (
    "net/http"
    "strings"
 
    "github.com/tameflare/tameflare/apps/gateway-v2/internal/connectors"
)
 
type JiraConnector struct{}
 
func (c *JiraConnector) Name() string {
    return "jira"
}
 
func (c *JiraConnector) Domains() []string {
    return []string{"your-org.atlassian.net"}
}
 
func (c *JiraConnector) ParseAction(req *http.Request) (*connectors.Action, error) {
    path := req.URL.Path
    method := req.Method
 
    var actionType string
    switch {
    case method == "POST" && strings.Contains(path, "/rest/api/3/issue"):
        actionType = "jira.issue.create"
    case method == "PUT" && strings.Contains(path, "/rest/api/3/issue"):
        actionType = "jira.issue.update"
    case method == "DELETE" && strings.Contains(path, "/rest/api/3/issue"):
        actionType = "jira.issue.delete"
    case method == "POST" && strings.Contains(path, "/rest/api/3/issue") && strings.Contains(path, "/transitions"):
        actionType = "jira.issue.transition"
    default:
        actionType = "jira." + strings.ToLower(method)
    }
 
    return &connectors.Action{
        Type: actionType,
        Resource: connectors.Resource{
            Provider: "jira",
        },
        RiskHints: map[string]any{
            "irreversible": method == "DELETE",
        },
    }, nil
}
 
func (c *JiraConnector) InjectCredentials(req *http.Request, cred *connectors.Credential) error {
    req.Header.Set("Authorization", "Basic "+cred.Token)
    return nil
}

Registering a custom connector

Add your connector to the registry in internal/connectors/registry.go:

func NewRegistry() *Registry {
    r := &Registry{connectors: make(map[string]Connector)}
    r.Register(&github.GitHubConnector{})
    r.Register(&openai.OpenAIConnector{})
    r.Register(&stripe.StripeConnector{})
    r.Register(&slack.SlackConnector{})
    r.Register(&generic.GenericConnector{})
    r.Register(&jira.JiraConnector{})  // Your custom connector
    return r
}

Rebuild the gateway after adding a connector:

cd apps/gateway-v2 && go build -o gateway ./cmd/gateway

Next steps