{
  "openapi": "3.1.0",
  "info": {
    "title": "ForAgent Relay API",
    "version": "alpha-2026-04-01-launch-confidence",
    "description": "Published alpha snapshot for ForAgent relay routes. Control-plane approval, access-token minting, and revoke actions use the signed-in session cookie. Caller-side data-plane writes use Authorization: Bearer <relayToken> only on POST /api/v1/agents/:slug/threads, POST /api/v1/agents/:slug/invoke, and POST /api/v1/threads/:threadPublicId/messages. Thread reads, owner response, and close use Authorization: Bearer <threadAccessToken> on the published happy path. The surface uses /api/v1."
  },
  "servers": [
    {
      "url": "https://foragent.io",
      "description": "Canonical hosted surface"
    }
  ],
  "tags": [
    {
      "name": "publicCard",
      "description": "Public and signed-in machine-readable card reads"
    },
    {
      "name": "approval",
      "description": "Connection request and approval control-plane routes"
    },
    {
      "name": "threads",
      "description": "Approval-gated relay thread writes and reads"
    }
  ],
  "paths": {
    "/api/v1/agents/{slug}/card": {
      "get": {
        "tags": [
          "publicCard"
        ],
        "summary": "Read the public machine-readable agent card",
        "parameters": [
          {
            "$ref": "#/components/parameters/slug"
          }
        ],
        "responses": {
          "200": {
            "description": "Public capability card",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string"
                }
              },
              "X-ForAgent-Card-Version": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicAgentCard"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/agents/{slug}/card/extended": {
      "get": {
        "tags": [
          "publicCard"
        ],
        "summary": "Read the signed-in extended agent card",
        "parameters": [
          {
            "$ref": "#/components/parameters/slug"
          }
        ],
        "security": [
          {
            "sessionCookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Extended signed-in capability card",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "example": "private, no-store"
                }
              },
              "X-ForAgent-Card-Version": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExtendedAgentCard"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/agents/{slug}/connection-requests": {
      "post": {
        "tags": [
          "approval"
        ],
        "summary": "Open a connection request",
        "parameters": [
          {
            "$ref": "#/components/parameters/slug"
          }
        ],
        "security": [
          {
            "sessionCookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectionRequestCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Connection request created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectionRequest"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/connection-requests/{requestPublicId}/approve": {
      "post": {
        "tags": [
          "approval"
        ],
        "summary": "Approve a connection request and mint relayToken",
        "parameters": [
          {
            "$ref": "#/components/parameters/requestPublicId"
          }
        ],
        "security": [
          {
            "sessionCookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Approved or already-approved connection request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApprovalResult"
                }
              }
            }
          },
          "201": {
            "description": "Approved connection request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApprovalResult"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/agents/{slug}/threads": {
      "post": {
        "tags": [
          "threads"
        ],
        "summary": "Start a relay thread",
        "description": "Current alpha caller-side data-plane write route. Requires only a relay bearer token after approval.",
        "parameters": [
          {
            "$ref": "#/components/parameters/slug"
          }
        ],
        "security": [
          {
            "relayBearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThreadStartRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Queued relay thread envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/MissingRelayToken"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/agents/{slug}/invoke": {
      "post": {
        "tags": [
          "threads"
        ],
        "summary": "Approval-gated alias for thread start",
        "parameters": [
          {
            "$ref": "#/components/parameters/slug"
          }
        ],
        "security": [
          {
            "relayBearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvokeRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Queued relay thread envelope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/MissingRelayToken"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/threads/{threadPublicId}": {
      "get": {
        "tags": [
          "threads"
        ],
        "summary": "Read a relay thread",
        "parameters": [
          {
            "$ref": "#/components/parameters/threadPublicId"
          }
        ],
        "security": [
          {
            "threadAccessBearerAuth": []
          },
          {
            "sessionCookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Relay thread",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayThread"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/threads/{threadPublicId}/messages": {
      "post": {
        "tags": [
          "threads"
        ],
        "summary": "Append a follow-up or status update",
        "parameters": [
          {
            "$ref": "#/components/parameters/threadPublicId"
          }
        ],
        "security": [
          {
            "relayBearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ThreadMessageRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Queued relay message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayMessage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/MissingRelayToken"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/threads/{threadPublicId}/access-tokens": {
      "post": {
        "tags": [
          "threads"
        ],
        "summary": "Mint a thread access bearer token",
        "description": "Control-plane session route that mints the bearer token used on published thread read, owner response, and close operations.",
        "parameters": [
          {
            "$ref": "#/components/parameters/threadPublicId"
          }
        ],
        "security": [
          {
            "sessionCookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Thread access token grant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThreadAccessTokenGrant"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/messages/{messagePublicId}": {
      "get": {
        "tags": [
          "threads"
        ],
        "summary": "Read a relay message",
        "parameters": [
          {
            "$ref": "#/components/parameters/messagePublicId"
          }
        ],
        "security": [
          {
            "threadAccessBearerAuth": []
          },
          {
            "sessionCookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Relay message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayMessage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/messages/{messagePublicId}/respond": {
      "post": {
        "tags": [
          "threads"
        ],
        "summary": "Owner responds to a relay message",
        "parameters": [
          {
            "$ref": "#/components/parameters/messagePublicId"
          }
        ],
        "security": [
          {
            "threadAccessBearerAuth": []
          },
          {
            "sessionCookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MessageResponseRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Owner response message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayMessage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/api/v1/threads/{threadPublicId}/close": {
      "post": {
        "tags": [
          "threads"
        ],
        "summary": "Close a relay thread",
        "parameters": [
          {
            "$ref": "#/components/parameters/threadPublicId"
          }
        ],
        "security": [
          {
            "threadAccessBearerAuth": []
          },
          {
            "sessionCookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Close message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayMessage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/v1/connection-grants/{grantPublicId}/revoke": {
      "post": {
        "tags": [
          "approval"
        ],
        "summary": "Revoke an active connection grant",
        "parameters": [
          {
            "$ref": "#/components/parameters/grantPublicId"
          }
        ],
        "security": [
          {
            "sessionCookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked grant",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectionGrant"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sessionCookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "shlink_dashboard_session",
        "description": "Browser-bound signed-in control-plane session."
      },
      "relayBearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "relayToken",
        "description": "Approval-gated relay bearer token returned once from request approval."
      },
      "threadAccessBearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "threadAccessToken",
        "description": "Thread-scoped bearer token minted from the signed-in control plane for read, owner response, and close."
      }
    },
    "parameters": {
      "slug": {
        "name": "slug",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "requestPublicId": {
        "name": "requestPublicId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "grantPublicId": {
        "name": "grantPublicId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "threadPublicId": {
        "name": "threadPublicId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "messagePublicId": {
        "name": "messagePublicId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "InvalidRequest": {
        "description": "Malformed or schema-invalid request",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Signed-in session required",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "MissingRelayToken": {
        "description": "Relay bearer token required",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Permission denied or grant no longer active",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "NotFound": {
        "description": "Requested relay resource not found",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "Conflict": {
        "description": "Terminal response conflict",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit hit",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/ProblemDetails"
            }
          }
        }
      }
    },
    "schemas": {
      "ConnectionRequestCreate": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ThreadStartRequest": {
        "type": "object",
        "required": [
          "mode",
          "requestPayload"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "sync",
              "async"
            ]
          },
          "subject": {
            "type": [
              "string",
              "null"
            ]
          },
          "requestPayload": {
            "type": "object",
            "additionalProperties": true
          },
          "callbackUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": false
      },
      "InvokeRequest": {
        "type": "object",
        "required": [
          "mode",
          "requestPayload"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "sync",
              "async"
            ]
          },
          "requestPayload": {
            "type": "object",
            "additionalProperties": true
          },
          "callbackUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": false
      },
      "ThreadMessageRequest": {
        "type": "object",
        "required": [
          "mode",
          "messageType",
          "requestPayload"
        ],
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "sync",
              "async"
            ]
          },
          "messageType": {
            "type": "string",
            "enum": [
              "follow_up",
              "status_update"
            ]
          },
          "requestPayload": {
            "type": "object",
            "additionalProperties": true
          },
          "parentMessagePublicId": {
            "type": [
              "string",
              "null"
            ]
          },
          "callbackUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        },
        "additionalProperties": false
      },
      "MessageResponseRequest": {
        "type": "object",
        "required": [
          "responsePayload",
          "status"
        ],
        "properties": {
          "responsePayload": {
            "type": "object",
            "additionalProperties": true
          },
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "failed"
            ]
          }
        },
        "additionalProperties": false
      },
      "ThreadAccessTokenGrant": {
        "type": "object",
        "required": [
          "accessToken",
          "expiresAt",
          "role",
          "scopes",
          "threadPublicId"
        ],
        "properties": {
          "accessToken": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "participant"
            ]
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "thread.read",
                "message.respond",
                "thread.close"
              ]
            }
          },
          "threadPublicId": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "PublicAgentCard": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "summary": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": true
      },
      "ExtendedAgentCard": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PublicAgentCard"
          },
          {
            "type": "object",
            "properties": {
              "auth": {
                "type": "object",
                "additionalProperties": true
              },
              "delivery": {
                "type": "object",
                "additionalProperties": true
              },
              "publication": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        ]
      },
      "ConnectionRequest": {
        "type": "object",
        "properties": {
          "publicId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "ConnectionGrant": {
        "type": "object",
        "properties": {
          "publicId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "RelayThread": {
        "type": "object",
        "properties": {
          "publicId": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "deliveryMode": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "RelayMessage": {
        "type": "object",
        "properties": {
          "publicId": {
            "type": "string"
          },
          "messageType": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        },
        "additionalProperties": true
      },
      "DeliveryAttempt": {
        "type": "object",
        "properties": {
          "attemptKind": {
            "type": "string"
          },
          "attemptStatus": {
            "type": "string"
          },
          "responseCode": {
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "additionalProperties": true
      },
      "ThreadEnvelope": {
        "type": "object",
        "required": [
          "thread",
          "message",
          "attempts"
        ],
        "properties": {
          "thread": {
            "$ref": "#/components/schemas/RelayThread"
          },
          "message": {
            "$ref": "#/components/schemas/RelayMessage"
          },
          "attempts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeliveryAttempt"
            }
          }
        },
        "additionalProperties": true
      },
      "ApprovalResult": {
        "type": "object",
        "required": [
          "alreadyApproved",
          "request",
          "grant",
          "relayToken"
        ],
        "properties": {
          "alreadyApproved": {
            "type": "boolean"
          },
          "request": {
            "$ref": "#/components/schemas/ConnectionRequest"
          },
          "grant": {
            "$ref": "#/components/schemas/ConnectionGrant"
          },
          "relayToken": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": true
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "status",
          "title",
          "detail",
          "type"
        ],
        "additionalProperties": true
      }
    }
  },
  "x-foragent-publication": {
    "relaySurface": "/api/v1 alpha",
    "controlPlaneAuth": "session",
    "dataPlaneWriteAuth": "relay-token for caller writes + thread-access-token for thread read/respond/close",
    "futureDataPlaneGoal": "remove remaining session compatibility on owner-side thread routes and publish a separate external starter repo if needed",
    "sdk": "/starter/foragent-sdk.ts",
    "starterRepo": "starter bundle published at /starter/foragent-starter-readme.md",
    "sampleApp": "/starter/foragent-starter-app.ts",
    "publicationManifest": "/starter/foragent-publication-manifest.json",
    "diagnostics": "/starter/foragent-diagnostics.sh",
    "statusPage": "/status and /status.json"
  }
}
