> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parmanasystems.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Propose registering or revoking an external connector

> Proposes registering an external connector (action register: a capability, the HTTPS endpoint to release it to, the policy that governs it, the parameters to forward, and optionally a timeout) or revoking the active one for a capability ...



## OpenAPI

````yaml openapi.bundled.yaml POST /external-connectors/changes
openapi: 3.1.0
info:
  title: Parmana API
  version: 1.0.0
  description: >
    Parmana is an Execution Trust Infrastructure that ensures there is no gap
    between what humans decide and what AI systems do. The API enables creation,
    execution, verification, replay, and auditing of Business Transactions
    through cryptographically verifiable Execution Trust Records.


    **Every route requires a caller bearer key**, except the liveness/readiness
    probes and documentation/verification routes that must be reachable with no
    credential: GET /health, GET /ready, GET /openapi.yaml, GET /documentation,
    GET /reference, POST /refusal/verify, POST /execution-intents/verify, POST
    /audit/verify, GET /keys/{keyId}, and GET /.well-known/jwks.json. Send
    `Authorization: Bearer <key>` on every other request. Keys are issued by
    `scripts/generate-api-key.ts` and configured server-side via
    `PARMANA_API_KEYS`; only a hash of each key is ever held by the server,
    verified in constant time. A missing or invalid credential returns 401
    before a Business Transaction is even constructed, independent of Policy
    evaluation and gateway attestation, see
    `packages/api/src/middleware/caller-auth.ts` and
    [Authentication](/api-reference/authentication). Local development may set
    `PARMANA_AUTH_DISABLED=true` to skip this middleware entirely; that flag
    must never be set in a real deployment.
  contact:
    name: Parmana Systems
    email: founder@parmanasystems.com
  license:
    name: Proprietary, source-available for evaluation only, see LICENSE
    url: https://github.com/pavancharak/AgentLabsBuildathon/blob/main/LICENSE
servers:
  - url: https://parmana-api-real.vercel.app
    description: >-
      Production (real, deployed instance -- the docs site playground uses this
      by default)
  - url: http://localhost:3000
    description: Local (packages/api, PORT env var, default 3000)
security:
  - bearerAuth: []
tags:
  - name: Execution
    description: >-
      Executes a Business Transaction through the complete Execution Trust
      pipeline
  - name: Transactions
    description: Business Transaction creation and retrieval
  - name: Verification
    description: Deterministic verification of an Execution Trust Record
  - name: Receipts
    description: Cryptographically signed Execution Trust Receipts
  - name: Trust Records
    description: Execution Trust Record retrieval
  - name: Replay
    description: Deterministic replay of a recorded Execution Trust Record
  - name: Policies
    description: Policy existence/readability check
  - name: Policy Governance
    description: Maker-checker proposal, listing, approval, and rejection of policy changes
  - name: Approvers
    description: Maker-checker for the keys trusted to sign approvals, without a deploy
  - name: External Connectors
    description: >-
      Maker-checker for binding a capability to an operator's HTTPS endpoint and
      its policy, without a deploy (ADR-0013)
  - name: Refusal Records
    description: >-
      Durable, signed evidence that a policy decision rejected a transaction
      (RFC-0021)
  - name: Execution Intents
    description: >-
      A signed statement, stored before an action is released, of exactly what
      is about to be released, plus the operator tools to find and repair a
      released action that has no signed Trust Record (ADR-0012)
  - name: Audit
    description: >-
      Signed caller-authentication audit events, independently
      third-party-verifiable
  - name: System
    description: Operational endpoints
paths:
  /external-connectors/changes:
    post:
      tags:
        - External Connectors
      summary: Propose registering or revoking an external connector
      description: >
        Proposes registering an external connector (action register: a
        capability, the HTTPS endpoint to release it to, the policy that governs
        it, the parameters to forward, and optionally a timeout) or revoking the
        active one for a capability (action revoke). Nothing changes until a
        different person approves the proposal. Requires a human credential. A
        capability in a built in connector's namespace (paytm, hubspot, github,
        slack, test) is refused. The endpoint must be https, name a host with a
        domain (not an IP address, not localhost), carry no user name, password
        or fragment, and resolve only to public addresses; the address is
        checked again when the change is approved. To move a capability to a new
        endpoint, revoke the registration, then register the new one.
      operationId: proposeExternalConnectorChange
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: >-
                #/components/schemas/propose-external-connector-change-request.schema
            examples:
              register:
                summary: Real captured request
                value:
                  action: register
                  capability: erp:create-invoice
                  endpointUrl: https://erp.example.com/parmana/release
                  policy: erp-invoice
                  allowedParameters:
                    - amount
                    - currency
                    - customerId
                  timeoutMs: 10000
                  reason: >-
                    Finance creates invoices in the ERP through Parmana from
                    October.
              revoke:
                summary: Real captured request
                value:
                  action: revoke
                  capability: erp:create-invoice
                  reason: The ERP endpoint moves to a new host.
      responses:
        '201':
          description: Proposed, PENDING_APPROVAL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/external-connector-change.schema'
              examples:
                register:
                  summary: Real captured response
                  value:
                    changeId: 1aa68ad8-ab5c-4beb-9ff3-7a6b1fc1ff37
                    action: register
                    capability: erp:create-invoice
                    endpointUrl: https://erp.example.com/parmana/release
                    policy: erp-invoice
                    allowedParameters:
                      - amount
                      - currency
                      - customerId
                    timeoutMs: 10000
                    reason: >-
                      Finance creates invoices in the ERP through Parmana from
                      October.
                    proposedBy: human-maker
                    proposedAt: '2026-09-30T17:25:46.316Z'
                    status: PENDING_APPROVAL
                revoke:
                  summary: Real captured response
                  value:
                    changeId: 5bdbfd6a-babf-4977-b090-d561ddcee0d7
                    action: revoke
                    capability: erp:create-invoice
                    reason: The ERP endpoint moves to a new host.
                    proposedBy: human-maker
                    proposedAt: '2026-09-30T17:25:46.418Z'
                    status: PENDING_APPROVAL
        '400':
          description: >-
            INVALID_EXTERNAL_CONNECTOR (a field is missing or malformed, the
            namespace belongs to a built in connector, or a revoke carries
            registration fields) or EXTERNAL_ENDPOINT_ADDRESS_REFUSED (the
            endpoint is not https, names an IP address or localhost, or resolves
            to an address that is not public, or does not resolve).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error.schema'
              examples:
                builtInNamespace:
                  summary: Real captured response
                  value:
                    error: >-
                      The namespace 'paytm' belongs to a built in connector. Use
                      another namespace.
                    code: INVALID_EXTERNAL_CONNECTOR
                privateAddress:
                  summary: Real captured response
                  value:
                    error: >-
                      The endpoint host 'erp-internal.example.com' resolves to
                      an address that is not public (10.0.0.7).
                    code: EXTERNAL_ENDPOINT_ADDRESS_REFUSED
                badCapability:
                  summary: Real captured response
                  value:
                    error: >-
                      capability must be namespace:verb, at most 128 characters,
                      matching
                      ^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*:[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$.
                    code: INVALID_EXTERNAL_CONNECTOR
                badTimeout:
                  summary: Real captured response
                  value:
                    error: >-
                      timeoutMs must be an integer from 1000 to 30000; it
                      defaults to 10000.
                    code: INVALID_EXTERNAL_CONNECTOR
                duplicateParameter:
                  summary: Real captured response
                  value:
                    error: >-
                      allowedParameters must be an array of at most 64 distinct
                      names, each matching ^[A-Za-z_][A-Za-z0-9_]{0,63}$.
                    code: INVALID_EXTERNAL_CONNECTOR
                revokeWithRegistrationFields:
                  summary: Real captured response
                  value:
                    error: A revoke takes only action, capability and reason.
                    code: INVALID_EXTERNAL_CONNECTOR
                plainHttp:
                  summary: Real captured response
                  value:
                    error: endpointUrl must use https.
                    code: EXTERNAL_ENDPOINT_ADDRESS_REFUSED
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: The caller is not a human credential (NON_HUMAN_CALLER_DENIED).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error.schema'
              examples:
                service:
                  summary: Real captured response, a service credential
                  value:
                    error: >-
                      This action requires a caller credential provisioned as a
                      verified human (credentialHolderType: USER).
                    code: NON_HUMAN_CALLER_DENIED
        '409':
          description: >-
            CONFLICT. The capability to register already has an active
            registration, the capability to revoke has none, or another change
            for this capability is pending.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error.schema'
              examples:
                pending:
                  summary: Real captured response
                  value:
                    error: >-
                      A change for capability 'erp:create-invoice' is already
                      pending. It must be approved or rejected first.
                    code: CONFLICT
                alreadyActive:
                  summary: Real captured response
                  value:
                    error: >-
                      Capability 'erp:create-invoice' already has an active
                      external connector. Revoke it first.
                    code: CONFLICT
                revokeUnregistered:
                  summary: Real captured response
                  value:
                    error: >-
                      Capability 'erp:create-invoice' has no active external
                      connector.
                    code: CONFLICT
components:
  schemas:
    propose-external-connector-change-request.schema:
      title: Propose External Connector Change Request
      description: >-
        Request body for POST /external-connectors/changes. A register carries
        endpointUrl, policy, allowedParameters and optionally timeoutMs; a
        revoke carries none of them.
      type: object
      additionalProperties: true
      required:
        - action
        - capability
        - reason
      properties:
        action:
          type: string
          enum:
            - register
            - revoke
        capability:
          type: string
          pattern: ^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*:[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$
          maxLength: 128
        endpointUrl:
          type: string
          maxLength: 2048
          description: Required for register. https only, a public host name.
        policy:
          type: string
          pattern: ^[a-z0-9][a-z0-9-]{0,127}$
          description: Required for register.
        allowedParameters:
          type: array
          maxItems: 64
          uniqueItems: true
          items:
            type: string
            pattern: ^[A-Za-z_][A-Za-z0-9_]{0,63}$
          description: Required for register. May be empty.
        timeoutMs:
          type: integer
          minimum: 1000
          maximum: 30000
          default: 10000
        reason:
          type: string
          minLength: 1
          maxLength: 2000
      examples:
        - action: register
          capability: erp:create-invoice
          endpointUrl: https://erp.example.com/parmana/release
          policy: erp-invoice
          allowedParameters:
            - amount
            - currency
            - customerId
          timeoutMs: 10000
          reason: Finance creates invoices in the ERP through Parmana from October.
        - action: revoke
          capability: erp:create-invoice
          reason: The ERP endpoint moves to a new host.
    external-connector-change.schema:
      title: External Connector Change
      description: >-
        A proposal to register an external connector, or to revoke the active
        one for a capability, and its resolution (ADR-0013). One person proposes
        it; a different person approves or rejects it with a step up
        authorization. Only an approved change affects which external connectors
        are registered.
      type: object
      additionalProperties: false
      required:
        - changeId
        - action
        - capability
        - reason
        - proposedBy
        - proposedAt
        - status
      properties:
        changeId:
          type: string
          description: >-
            Unique id of the change, a UUID. The step up authorization for
            approve or reject names it in payload.pendingPolicyChangeId. An
            approved register change's id is also the registrationId.
        action:
          type: string
          enum:
            - register
            - revoke
          description: >-
            register binds the capability to the endpoint; revoke ends the
            active registration for the capability.
        capability:
          type: string
          pattern: ^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*:[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$
          maxLength: 128
          description: >-
            namespace:verb. Never in a built in connector's namespace (paytm,
            hubspot, github, slack, test).
        endpointUrl:
          type: string
          description: >-
            register only. The endpoint as the server stored it, normalized by
            URL parsing: https, a host name with a domain, no IP literal, no
            localhost, no user name, password or fragment, resolving only to
            public addresses. It is the audience of every release to this
            endpoint.
        policy:
          type: string
          pattern: ^[a-z0-9][a-z0-9-]{0,127}$
          description: >-
            register only. The name of the policy that governs the capability.
            The version in effect is decided by policy governance.
        allowedParameters:
          type: array
          maxItems: 64
          uniqueItems: true
          items:
            type: string
            pattern: ^[A-Za-z_][A-Za-z0-9_]{0,63}$
          description: >-
            register only. The only parameter names Parmana will forward to the
            endpoint.
        timeoutMs:
          type: integer
          minimum: 1000
          maximum: 30000
          description: >-
            register only. How long Parmana waits for the endpoint's answer.
            Defaults to 10000.
        reason:
          type: string
          maxLength: 2000
          description: Why, from the proposer.
        proposedBy:
          type: string
          description: The proposer's caller id. Always a human credential.
        proposedAt:
          type: string
          format: date-time
        status:
          type: string
          enum:
            - PENDING_APPROVAL
            - APPROVED
            - REJECTED
          description: >-
            PENDING_APPROVAL until a second person approves or rejects it; then
            APPROVED or REJECTED, once.
        resolvedBy:
          type: string
          description: Who approved or rejected it. Never the proposer.
        resolvedAt:
          type: string
          format: date-time
        rejectionReason:
          type: string
          description: Present when REJECTED.
      examples:
        - changeId: 1aa68ad8-ab5c-4beb-9ff3-7a6b1fc1ff37
          action: register
          capability: erp:create-invoice
          endpointUrl: https://erp.example.com/parmana/release
          policy: erp-invoice
          allowedParameters:
            - amount
            - currency
            - customerId
          timeoutMs: 10000
          reason: Finance creates invoices in the ERP through Parmana from October.
          proposedBy: human-maker
          proposedAt: '2026-09-30T17:25:46.316Z'
          status: APPROVED
          resolvedBy: human-checker
          resolvedAt: '2026-09-30T17:25:46.385Z'
    error.schema:
      title: Error Response
      description: >-
        Shared error envelope produced by
        packages/api/src/middleware/error-handler.ts and by every route's inline
        validation checks. error is always a plain human-readable string (never
        a nested object). code is present only when the failure was a
        RuntimeError subclass reaching the centralized error handler
        (VerificationFailedError, ReceiptGenerationError, or an uncategorized
        RuntimeError); it is absent from every inline route-level check
        (businessTransactionId format/required checks) and from
        BusinessTransactionValidationError, PolicyValidationError,
        SignalValidationError, PolicyNotFoundError,
        DuplicateBusinessTransactionError, and the generic 500 fallback. POST
        /policies/validate does NOT use this envelope at all. See its own
        response schema. For the triggering condition and recommended caller
        action behind any specific error/code/status combination, see the Error
        catalog at /api-reference/error-catalog.
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable error message.
        code:
          type: string
          description: >-
            Stable machine-readable error code. Only present for errors that
            reach the handler as a RuntimeError.
          examples:
            - RUNTIME_ERROR
            - VERIFICATION_FAILED
            - RECEIPT_GENERATION_FAILED
            - POLICY_DENIED
            - CAPABILITY_NOT_ALLOWED
            - RATE_LIMITED
            - AUDIT_UNAVAILABLE
            - SIGNING_UNAVAILABLE
            - CONNECTOR_NOT_REGISTERED
            - EXECUTION_RECORD_INCOMPLETE
            - EXECUTION_INTENT_UNAVAILABLE
            - EXECUTION_INTENT_RESULT_NOT_RECORDED
            - EXECUTION_INTENT_NOT_FOUND
            - EXECUTION_INTENTS_NOT_ENABLED
            - EXECUTION_INTENT_NOT_RESOLVABLE
            - EXECUTION_INTENT_RESOLUTION_INVALID
            - NON_HUMAN_CALLER_DENIED
      examples:
        - error: businessTransactionId must be a valid UUID.
        - error: >-
            Business Transaction 'eed2a972-1bf5-4166-8472-761f76fbf1b2' already
            exists.
        - error: >-
            Execution rejected: Vendor payment rejected because the assessed
            payment risk exceeds the maximum permitted threshold.
          code: RUNTIME_ERROR
  responses:
    Unauthorized:
      description: >-
        Missing or invalid caller credential (StaticKeyAuthenticator returned no
        identity). Real captured response,
        packages/api/src/middleware/caller-auth.ts.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/error.schema'
          examples:
            authRequired:
              summary: Real captured response, missing or invalid Authorization header
              value:
                error: authentication required
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >
        Caller API key issued by scripts/generate-api-key.ts. Sent as
        Authorization: Bearer <key>. Verified against a stored SHA-256 hash in
        constant time by packages/api/src/auth/StaticKeyAuthenticator.ts.
        Required on every route not listed as exempt in this document's
        top-level description. See /api-reference/authentication.

````