openapi: 3.2.0 info: title: mcpgate-backend Subscription Gateway API version: 0.4.20 tags: - name: subscription-gateway paths: /subscription/{jti}/bind: post: tags: - subscription-gateway summary: Bind Subscription description: 'A gateway claims this subscription with its instance_token. Auth chain: 1. Caller sends the JWT in `X-Subscription-Token` (proves possession). 2. Backend verifies the signature against its own public key and checks the jti matches the URL. 3. If valid and the subscription is not revoked, the row''s `instance_token` is set (idempotent, allows rebind to a new instance).' operationId: bind_subscription_subscription__jti__bind_post parameters: - name: jti in: path required: true schema: type: string minLength: 1 maxLength: 64 title: Jti - name: X-Subscription-Token in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Subscription-Token requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BindRequest' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/BindResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /subscription/refresh: get: tags: - subscription-gateway summary: Refresh Subscription description: 'Return a fresh JWT for the calling gateway. The gateway authenticates with the same `instance_token` it received from `/feedback/register` (and which was attached to the subscription row via `/{jti}/bind`). On every refresh we re-sign with a rolling `REFRESH_WINDOW_DAYS` window, capped by the subscription''s own `expires_at` (the contract end-date). A revoked subscription returns 410. An unbound or unknown instance_token returns 404 — the gateway treats both as "no subscription on file" and falls back to its locally-stored JWT, which keeps working until its own exp is reached.' operationId: refresh_subscription_subscription_refresh_get parameters: - name: X-Instance-Token in: header required: false schema: anyOf: - type: string - type: 'null' title: X-Instance-Token responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/RefreshResponse' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' components: schemas: BindRequest: properties: instance_token: type: string maxLength: 64 minLength: 16 title: Instance Token type: object required: - instance_token title: BindRequest description: 'A gateway claims a subscription with its `instance_token` so it can later pull refreshed tokens. The instance_token is the random hex the gateway received from `/feedback/register`; the backend never has to issue a separate credential for the subscription channel.' HTTPValidationError: properties: detail: items: $ref: '#/components/schemas/ValidationError' type: array title: Detail type: object title: HTTPValidationError BindResponse: properties: jti: type: string title: Jti bound_at: type: string format: date-time title: Bound At type: object required: - jti - bound_at title: BindResponse RefreshResponse: properties: jti: type: string title: Jti tier: type: string enum: - team - enterprise title: Tier issued_to: type: string title: Issued To expires_at: type: string format: date-time title: Expires At kid: type: string title: Kid token: type: string title: Token refreshed_at: type: string format: date-time title: Refreshed At type: object required: - jti - tier - issued_to - expires_at - kid - token - refreshed_at title: RefreshResponse description: 'Returned by `/subscription/refresh` when the calling gateway has a valid binding. The gateway overwrites its stored token with `token`.' ValidationError: properties: loc: items: anyOf: - type: string - type: integer type: array title: Location msg: type: string title: Message type: type: string title: Error Type input: title: Input ctx: type: object title: Context type: object required: - loc - msg - type title: ValidationError