{
  "schema": "aaes/capability-pack/1",
  "provider": "freshdesk",
  "version": "1.0.0",
  "description": "Read Freshdesk tickets, contacts, and agents; reply to tickets and add notes. Replies reach the requester, and notes can be public or trigger email notifications.",
  "notes": "The endpoint host 'your-domain.freshdesk.invalid' is a reserved non-production placeholder (.invalid is an RFC 2606 reserved TLD that can never resolve): substitute the account's own Freshdesk domain (your-domain.freshdesk.com — the account's Freshdesk domain; this review did not find Freshdesk API documentation supporting a custom support URL as an interchangeable API destination, so none is offered) before enabling, in the endpoints, the resource locators and the egress allowlist — the allowlist matches exactly, so all three must be substituted together, and substitution is a required pre-enablement step.\n\nNote that allowlisting the reserved placeholder host does not make an unsubstituted pack safe: an unsubstituted pack has never been bound to the account it claims to govern, and its review says nothing about that account. This pack registers only endpoints the official Freshdesk API documentation (developers.freshdesk.com/api) lists: the tickets, contacts and agents collection reads, and creating a reply or a note on a ticket.\n\nAll read capabilities cover the collection read only: single-record reads (GET /api/v2/tickets/[id], /api/v2/contacts/[id], /api/v2/agents/[id]), search and filter endpoints (/api/v2/search/...), autocomplete, and ticket sub-resource listings (conversations, time_entries, watchers, accesses) are not registered by this pack — separate navigation and sub-resource endpoints are not registered unless named. Consequential effects: a Freshdesk reply is the public, customer-facing response on a ticket — it is delivered to the requester on the ticket's channel (typically email), so reply creation declares send at the minimum R3 tier alongside create.\n\nNote creation is judged by the same effect rule: Freshdesk documents notes as private by default, but the same endpoint accepts private=false (a public note the requester can see) and a notify_emails array (email addresses of agents or users 'who need to be notified about this note') — the unrestricted effect of the endpoint includes transmitting to people, so note creation also declares send at the minimum R3 tier. send is one of the designated actions requiring human approval: a delivered reply or notification cannot be recalled after delivery.\n\nA private-note-only variant is not registered as R2: the private flag and notify_emails are request-body properties of the same endpoint, and a pack registers an endpoint, not a body value, so nothing in the registration would enforce the restriction.\n\nDocumented exclusions: this pack does not register ticket create or update (a created ticket can email the requester and would likewise carry send), outbound email tickets (/api/v2/tickets/outbound_email), forward and reply_to_forward, ticket delete/restore, merge, bulk update, canned responses, contact create/update/delete or merge, agent create/update/delete, and the outbound-messages channel API.\n\nData-class rationale: tickets and contacts identify individuals and carry their correspondence, so both are pii; agents are the helpdesk's own staff directory (names, emails, roles) and are registered pii — staff names and email addresses are personal data whether they identify employees or customers.\n\nThe endpoints are verified against the provider documents named in the review block, and the custody review that docs/gtm/CAPABILITY-LIBRARY-PLAN.md §4 gates authentication modes on was completed on 2026-09-21 against this pack's custody model (an agent's API key used as HTTP Basic credentials, held in the customer's vault), with these findings, one per gated property.\n\nIssuance authority and delegation: each agent finds or regenerates their own API key in their Freshdesk profile settings, so issuance authority sits with the account's own agents and admins; the key authenticates AS that agent and delegates the agent's full role permissions to every call. Scope: Freshdesk documents no per-key scoping — the key inherits the agent's role permissions, so least privilege is achieved by issuing the key from a dedicated service-account agent whose role covers exactly the registered capabilities and nothing more.\n\nAudience: no audience mechanism is documented — the Basic credential authorizes against the account's freshdesk.com domain, and audience binding beyond that is not established. TTL: API keys do not expire on their own and stay live until regenerated or revoked.\n\nRefresh ownership: there is no refresh — the key is the credential and no tokens are derived from it; re-issuance is an external administrative action, and the executor injects the stored value verbatim and performs no credential lifecycle itself.\n\nRevocation: regenerating the key in profile settings invalidates the previous key immediately, and deleting or deactivating the agent disables its key; because no derived tokens exist, regeneration is full revocation of this value. Executor access and replay/exposure: the executor reads only the vault reference; the credential is replayable with no TTL bound until regenerated, so the vault reference is the only place the value may live.\n\nAlternate access paths: the Freshdesk web UI, other agents' keys and other integrations retain access outside this pack, and regenerating or deleting this key closes only this path. The credential review is complete. Assign accountable owners before deployment.",
  "credential": {
    "secret_ref_id": "secret-ref-freshdesk-api-key",
    "custody": "customer_vault",
    "inject": "header",
    "inject_name": "Authorization",
    "note": "A Freshdesk API key used as HTTP Basic credentials, held in the client's own secret manager. Freshdesk's documentation authenticates with the API key as the Basic-auth username and any single character (conventionally 'X') as the password ('curl -u apikey:X'), so the stored material must be the complete Authorization header value: the scheme 'Basic', one separating space, then the Base64 encoding of '{api_key}:X' — 'Basic <base64>'.\n\nKey issuance is an external process: each agent finds or regenerates their own API key in their Freshdesk profile settings; the executor performs no credential lifecycle itself and injects the stored value verbatim.\n\nLeast privilege: an API key authenticates AS that agent and inherits the agent's full role permissions, so issue the key from a dedicated least-privilege service-account agent whose role covers exactly the registered capabilities (read tickets, contacts and agents; reply and note on tickets) and nothing more.\n\nExpiry and revocation: API keys do not expire on their own; regenerating the key in profile settings invalidates the previous key immediately, and deleting or deactivating the agent disables its key. Because the key is the credential (no separate tokens are issued from it), regeneration is full revocation of this value — no already-issued tokens survive it, because none exist. Review the owning agent's role and the account's key inventory before enabling.\n\nExecutor hygiene: the value must live only in executor memory for the lifetime of a call, must never be written to logs, traces or diagnostics, and must not appear in crash dumps; a deployment that cannot meet that bar must not enable the pack."
  },
  "capabilities": [
    {
      "capability_id": "freshdesk.tickets.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "your-domain.freshdesk.invalid"
      ],
      "endpoint": "https://your-domain.freshdesk.invalid/api/v2/tickets",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-freshdesk-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "freshdesk-account-tickets",
      "description": "List all tickets: subjects, descriptions, requester and responder ids, statuses and cc lists, which identify individuals and carry their correspondence. The registered path covers the collection read only — single-ticket reads (GET /api/v2/tickets/[id]), search/filter and conversation or time-entry listings are not registered by this pack.",
      "requires_review": true
    },
    {
      "capability_id": "freshdesk.contacts.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "your-domain.freshdesk.invalid"
      ],
      "endpoint": "https://your-domain.freshdesk.invalid/api/v2/contacts",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-freshdesk-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "freshdesk-account-contacts",
      "description": "List all contacts: names, email addresses, phone numbers, job titles and addresses, which are personal data. The registered path covers the collection read only — single-contact reads (GET /api/v2/contacts/[id]), contact search/filter and autocomplete are not registered by this pack.",
      "requires_review": true
    },
    {
      "capability_id": "freshdesk.agents.read",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R0",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "your-domain.freshdesk.invalid"
      ],
      "endpoint": "https://your-domain.freshdesk.invalid/api/v2/agents",
      "method": "GET",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-freshdesk-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "read"
      ],
      "resource_id": "freshdesk-account-agents",
      "description": "List the helpdesk's agents: names, email addresses, roles, and group memberships. This staff directory is classified as pii (personal data), just as customer contact data is. Single-agent reads (GET /api/v2/agents/[id]) and /api/v2/agents/me are not registered.",
      "requires_review": true
    },
    {
      "capability_id": "freshdesk.tickets.reply.create",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "your-domain.freshdesk.invalid"
      ],
      "endpoint": "https://your-domain.freshdesk.invalid/api/v2/tickets/TICKET_ID/reply",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-freshdesk-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "send"
      ],
      "resource_id": "freshdesk-account-tickets",
      "description": "Create a reply on one ticket (an HTML body, with optional attachments and cc). The declared effect includes send at the minimum R3 tier: a reply is the public, customer-facing response on the ticket and is delivered to the requester on the ticket's channel (typically email) — a reply cannot be recalled after delivery once the requester has it. send is one of the designated actions requiring human approval.\n\nOn supported AAES-mediated execution paths, irreversible actions require approval by an authorized person; this does not prevent calls through bypass or observation-only paths. TICKET_ID is a placeholder the deployment binds to a concrete ticket before enabling.",
      "requires_review": true
    },
    {
      "capability_id": "freshdesk.tickets.notes.create",
      "version": "1.0.0",
      "kind": "tool",
      "risk_tier": "R3",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN",
      "data_class": "pii",
      "egress_allowlist": [
        "your-domain.freshdesk.invalid"
      ],
      "endpoint": "https://your-domain.freshdesk.invalid/api/v2/tickets/TICKET_ID/notes",
      "method": "POST",
      "connector": "http",
      "custody": "customer_vault",
      "secret_ref_id": "secret-ref-freshdesk-api-key",
      "inject": "header",
      "inject_name": "Authorization",
      "actions": [
        "create",
        "send"
      ],
      "resource_id": "freshdesk-account-tickets",
      "description": "Create a note on a ticket. Notes are private by default, but callers can set private=false to make a note visible to the requester or include notify_emails to send notifications to agents or users. This unrestricted endpoint therefore declares create and send at R3; send requires human approval. Delivered notifications cannot be recalled.\n\nThe pack has no private-note-only R2 variant: the registration cannot enforce values for private or notify_emails. Bind TICKET_ID to a concrete ticket before enabling.",
      "requires_review": true
    }
  ],
  "resources": [
    {
      "resource_id": "freshdesk-account-tickets",
      "kind": "api",
      "locator": "https://your-domain.freshdesk.invalid/api/v2/tickets",
      "data_class": "pii",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "freshdesk-account-contacts",
      "kind": "api",
      "locator": "https://your-domain.freshdesk.invalid/api/v2/contacts",
      "data_class": "pii",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    },
    {
      "resource_id": "freshdesk-account-agents",
      "kind": "api",
      "locator": "https://your-domain.freshdesk.invalid/api/v2/agents",
      "data_class": "pii",
      "owner": "REPLACE-WITH-ACCOUNTABLE-HUMAN"
    }
  ],
  "review": {
    "state": "library",
    "date": "2026-09-22",
    "sources": [
      "https://developers.freshdesk.com/api/ (retrieved 2026-09-21)"
    ],
    "reviewer_id": "aaes-eng"
  }
}
