{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"IS Jobs API","version":"1.1.0","description":"Search and read the published Information Systems jobs database, submit jobs, and manage a private job-market application tracker. Responses include canonical IS Jobs permalinks. OAuth access tokens and personal API tokens use the same scoped bearer authentication model."},"servers":[{"url":"https://isjobs.xyz","description":"IS Jobs"}],"tags":[{"name":"Jobs","description":"Public job discovery and submission."},{"name":"Tracker","description":"Private application tracker management."},{"name":"Tokens","description":"Personal API token and OAuth-connection management."},{"name":"OAuth","description":"OAuth client registration and token lifecycle."},{"name":"MCP","description":"Model Context Protocol Streamable HTTP transport."}],"paths":{"/api/v1/jobs":{"get":{"operationId":"listJobs","summary":"List published jobs","description":"Returns published jobs. Results can be filtered by season, text, job type, and region.","tags":["Jobs"],"security":[],"parameters":[{"name":"q","in":"query","required":false,"description":"Full-text query across position, university, department, region, and job type.","schema":{"type":"string","maxLength":200}},{"name":"season","in":"query","required":false,"description":"Season slug, such as 2026.","schema":{"type":"string","minLength":1,"maxLength":32}},{"name":"type","in":"query","required":false,"description":"Job types to include. Repeat the parameter to select multiple values.","style":"form","explode":true,"schema":{"type":"array","items":{"$ref":"#/components/schemas/JobType"}}},{"name":"region","in":"query","required":false,"description":"Regions to include. Repeat the parameter to select multiple values.","style":"form","explode":true,"schema":{"type":"array","items":{"$ref":"#/components/schemas/Region"}}},{"name":"limit","in":"query","required":false,"description":"Maximum number of jobs to return.","schema":{"type":"integer","minimum":1,"maximum":1000,"default":50}},{"name":"offset","in":"query","required":false,"description":"Number of matching jobs to skip for pagination.","schema":{"type":"integer","minimum":0,"maximum":10000,"default":0}}],"responses":{"200":{"description":"Published jobs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobListResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"submitJob","summary":"Submit a job","description":"Submits a job as the authenticated user. Valid submissions are published immediately.","tags":["Jobs"],"security":[{"oauth2":["jobs:write"]},{"bearerToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobSubmissionRequest"}}}},"responses":{"201":{"description":"Job published.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobSubmissionResponse"}}}},"400":{"$ref":"#/components/responses/InvalidJson"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/DuplicateJob"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedJsonMediaType"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/v1/jobs/{slug}":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Stable job slug.","schema":{"type":"string","minLength":1,"maxLength":240,"pattern":"^[a-z0-9]+(?:[-_][a-z0-9]+)*$"}}],"get":{"operationId":"getJob","summary":"Get a published job","description":"Returns one published job from the IS Jobs database by its stable slug.","tags":["Jobs"],"security":[],"responses":{"200":{"description":"Published job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/v1/tracker/applications":{"get":{"operationId":"listTrackerApplications","summary":"List tracker applications","description":"Lists application tracker entries owned by the authenticated user.","tags":["Tracker"],"security":[{"oauth2":["tracker:read"]},{"bearerToken":[]}],"parameters":[{"name":"status","in":"query","required":false,"description":"Application statuses to include. Repeat the parameter for multiple values.","style":"form","explode":true,"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApplicationStatus"}}}],"responses":{"200":{"description":"Tracker applications.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createTrackerApplication","summary":"Create a tracker application","description":"Tracks either an existing public job or an external opportunity.","tags":["Tracker"],"security":[{"oauth2":["tracker:write"]},{"bearerToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationCreateRequest"}}}},"responses":{"201":{"description":"Tracker application created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"400":{"$ref":"#/components/responses/InvalidJson"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/AlreadyTracked"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedJsonMediaType"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/v1/tracker/applications/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"Application identifier.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getTrackerApplication","summary":"Get a tracker application","description":"Returns an application tracker entry owned by the authenticated user.","tags":["Tracker"],"security":[{"oauth2":["tracker:read"]},{"bearerToken":[]}],"responses":{"200":{"description":"Tracker application.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"patch":{"operationId":"updateTrackerApplication","summary":"Update a tracker application","description":"Updates mutable fields on an application tracker entry owned by the authenticated user.","tags":["Tracker"],"security":[{"oauth2":["tracker:write"]},{"bearerToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationUpdateRequest"}}}},"responses":{"200":{"description":"Tracker application updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationResponse"}}}},"400":{"$ref":"#/components/responses/InvalidJson"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedJsonMediaType"},"422":{"$ref":"#/components/responses/ValidationError"}}},"delete":{"operationId":"deleteTrackerApplication","summary":"Delete a tracker application","description":"Permanently deletes an application tracker entry and its timeline events.","tags":["Tracker"],"security":[{"oauth2":["tracker:write"]},{"bearerToken":[]}],"responses":{"204":{"description":"Tracker application deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/v1/tracker/applications/{id}/events":{"parameters":[{"name":"id","in":"path","required":true,"description":"Application identifier.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listTrackerApplicationEvents","summary":"List application events","description":"Lists timeline events for an application tracker entry owned by the authenticated user.","tags":["Tracker"],"security":[{"oauth2":["tracker:read"]},{"bearerToken":[]}],"responses":{"200":{"description":"Application timeline events.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationEventListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createTrackerApplicationEvent","summary":"Add an application event","description":"Adds a note to the timeline of an application tracker entry owned by the authenticated user.","tags":["Tracker"],"security":[{"oauth2":["tracker:write"]},{"bearerToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationEventCreateRequest"}}}},"responses":{"201":{"description":"Application timeline event created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationEventResponse"}}}},"400":{"$ref":"#/components/responses/InvalidJson"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedJsonMediaType"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/v1/tokens":{"get":{"operationId":"listApiTokens","summary":"List API credentials and OAuth connections","description":"Lists personal-token metadata and one entry per OAuth grant family. Raw token secrets are never returned.","tags":["Tokens"],"security":[{"sessionCookie":[]}],"responses":{"200":{"description":"API access metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiTokenListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/ValidationError"}}},"post":{"operationId":"createApiToken","summary":"Create a personal API token","description":"Creates a scoped personal API token. The raw token is returned exactly once.","tags":["Tokens"],"security":[{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiTokenCreateRequest"}}}},"responses":{"201":{"description":"Personal API token created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiTokenCreatedResponse"}}}},"400":{"$ref":"#/components/responses/InvalidJson"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedJsonMediaType"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/api/v1/tokens/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"API credential or OAuth connection identifier.","schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"deleteApiToken","summary":"Revoke an API credential or OAuth connection","description":"Revokes a personal token or the full OAuth refresh-token family owned by the authenticated user.","tags":["Tokens"],"security":[{"sessionCookie":[]}],"responses":{"204":{"description":"API access revoked."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationError"}}}},"/oauth/authorize":{"get":{"operationId":"authorizeOAuthClient","summary":"Authorize an OAuth client","description":"Authenticated consent endpoint for authorization-code flow with mandatory S256 PKCE.","tags":["OAuth"],"security":[],"parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","const":"code"}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","format":"uri"}},{"name":"scope","in":"query","required":true,"schema":{"type":"string"}},{"name":"state","in":"query","required":false,"description":"Opaque client state returned unchanged.","schema":{"type":"string","maxLength":1024}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string","minLength":43,"maxLength":43}},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","const":"S256"}},{"name":"resource","in":"query","required":true,"schema":{"type":"string","format":"uri"}}],"responses":{"200":{"description":"Consent page."},"303":{"description":"Redirect to sign-in or back to the registered client."},"400":{"description":"Invalid authorization request."}}}},"/oauth/token":{"post":{"operationId":"exchangeOAuthToken","summary":"Exchange an OAuth grant","description":"Exchanges a one-time authorization code with S256 verifier or rotates a refresh token.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OAuthTokenRequest"}}}},"responses":{"200":{"description":"OAuth token response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthTokenResponse"}}}},"400":{"description":"OAuth protocol error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"Invalid client.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"413":{"description":"OAuth request body is too large.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"Token endpoint rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/oauth/revoke":{"post":{"operationId":"revokeOAuthToken","summary":"Revoke an OAuth token","description":"Revokes an OAuth access or refresh token as defined by RFC 7009.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/OAuthRevocationRequest"}}}},"responses":{"200":{"description":"The token is revoked or was already inactive."},"400":{"description":"OAuth protocol error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"413":{"description":"OAuth request body is too large.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"Revocation endpoint rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/oauth/register":{"post":{"operationId":"registerOAuthClient","summary":"Register an OAuth client","description":"Dynamically registers an OAuth client for authorization-code flow with PKCE.","tags":["OAuth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthClientRegistrationRequest"}}}},"responses":{"201":{"description":"OAuth client registered.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthClientRegistrationResponse"}}}},"400":{"description":"Invalid client metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"413":{"description":"OAuth request body is too large.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"429":{"description":"Registration rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/mcp":{"post":{"operationId":"handleMcpRequest","summary":"Send an MCP request","description":"Handles a JSON-RPC 2.0 request using the MCP Streamable HTTP transport. Individual tools enforce their declared OAuth scopes.","tags":["MCP"],"security":[{"oauth2":[]},{"bearerToken":[]}],"parameters":[{"name":"MCP-Protocol-Version","in":"header","required":false,"description":"Negotiated MCP protocol version. Required on follow-up requests; current versions reject JSON-RPC batches.","schema":{"type":"string","enum":["2025-11-25","2025-06-18","2025-03-26","2024-11-05","2024-10-07"]}},{"name":"Mcp-Session-Id","in":"header","required":false,"description":"Session identifier returned by a stateful MCP initialization response.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpRequest"}}}},"responses":{"200":{"description":"MCP JSON-RPC response or server-sent event stream.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpResponse"}},"text/event-stream":{"schema":{"type":"string"}}}},"202":{"description":"MCP notification accepted."},"400":{"description":"Malformed JSON or invalid MCP JSON-RPC request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"406":{"description":"The Accept header must allow both application/json and text/event-stream.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"}}}},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"description":"Content-Type must be application/json.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcErrorResponse"}}}},"422":{"$ref":"#/components/responses/ValidationError"}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","description":"OAuth 2.1 authorization-code flow with mandatory S256 PKCE.","flows":{"authorizationCode":{"authorizationUrl":"/oauth/authorize","tokenUrl":"/oauth/token","refreshUrl":"/oauth/token","scopes":{"jobs:read":"Search and read published jobs through authenticated MCP tools.","jobs:write":"Submit jobs to the IS Jobs database.","tracker:read":"Read the authenticated user's private application tracker.","tracker:write":"Create, update, and delete entries in the authenticated user's private application tracker."}}}},"bearerToken":{"type":"http","scheme":"bearer","bearerFormat":"Opaque","description":"A personal API token or OAuth access token."},"sessionCookie":{"type":"apiKey","in":"cookie","name":"isjobs_session","description":"Authenticated browser session. Used to create tokens and revoke personal or OAuth access."}},"responses":{"Unauthorized":{"description":"Authentication is missing, invalid, expired, or revoked.","headers":{"WWW-Authenticate":{"description":"Bearer challenge, including protected-resource metadata when applicable.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"The credential is valid but lacks the required scope or permission.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"The requested resource does not exist or is not visible to the authenticated user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ValidationError":{"description":"The request did not satisfy the operation schema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InvalidJson":{"description":"The request body does not contain valid JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"PayloadTooLarge":{"description":"The request body exceeds the operation's configured size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"UnsupportedJsonMediaType":{"description":"Content-Type must be application/json.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"DuplicateJob":{"description":"A job with the submitted canonical URL already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DuplicateJobErrorResponse"}}}},"AlreadyTracked":{"description":"The public job is already present in the authenticated user's tracker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlreadyTrackedErrorResponse"}}}}},"schemas":{"ApiScope":{"type":"string","enum":["jobs:read","jobs:write","tracker:read","tracker:write"]},"JobType":{"type":"string","enum":["Assistant Professor","Associate Professor","Professor","Post-doc","Other","Teaching Faculty"]},"TenureTrack":{"type":"string","enum":["tenure_track","non_tenure_track","unsure"]},"Region":{"type":"string","enum":["Africa","Asia","Europe","Middle East","North America","Oceania","Other","South America"]},"JobStatus":{"type":"string","enum":["pending","published","archived","rejected"]},"ApplicationStatus":{"type":"string","enum":["saved","preparing","applied","screening","interview","campus_visit","offer","accepted","rejected","withdrawn"]},"ApplicationPriority":{"type":"string","enum":["low","medium","high"]},"ErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["message"],"properties":{"path":{"type":"string"},"message":{"type":"string"}}}}}},"requestId":{"type":"string","format":"uuid"}}},"DuplicateJobErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","const":"duplicate_job"},"message":{"type":"string"}}}}},"AlreadyTrackedErrorResponse":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","const":"already_tracked"},"message":{"type":"string"}}}}},"Job":{"type":"object","additionalProperties":false,"required":["id","slug","positionName","university","universityId","schoolDepartment","url","type","tenureTrack","deadline","region","status","seasonSlug","seasonName","permalink","seasonPermalink","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"positionName":{"type":"string","minLength":3,"maxLength":200},"university":{"type":"string","minLength":2,"maxLength":200},"universityId":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"schoolDepartment":{"type":"string","maxLength":300},"url":{"type":"string","format":"uri","maxLength":2048,"description":"Original employer posting URL."},"type":{"type":"array","minItems":1,"uniqueItems":true,"items":{"$ref":"#/components/schemas/JobType"}},"tenureTrack":{"$ref":"#/components/schemas/TenureTrack"},"deadline":{"oneOf":[{"type":"string","format":"date"},{"type":"string","const":""}]},"region":{"$ref":"#/components/schemas/Region"},"status":{"$ref":"#/components/schemas/JobStatus"},"seasonSlug":{"type":"string"},"seasonName":{"type":"string"},"permalink":{"description":"Stable IS Jobs page for this job. Null while a submitted job is not publicly visible.","oneOf":[{"type":"string","format":"uri"},{"type":"null"}]},"seasonPermalink":{"description":"Stable IS Jobs page for the job's season, or null when the job has no public season.","oneOf":[{"type":"string","format":"uri"},{"type":"null"}]},"submissionPermalink":{"type":"string","format":"uri","description":"Authenticated dashboard page where the submitter can review the submission."},"submitterName":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"JobSubmissionRequest":{"type":"object","additionalProperties":false,"required":["positionName","university","url","type","tenureTrack","region"],"properties":{"seasonId":{"type":"string","format":"uuid"},"universityId":{"type":"string","format":"uuid"},"positionName":{"type":"string","minLength":3,"maxLength":200},"university":{"type":"string","minLength":2,"maxLength":200},"schoolDepartment":{"type":"string","maxLength":300,"default":""},"url":{"type":"string","format":"uri","maxLength":2048,"pattern":"^https?://"},"type":{"type":"array","minItems":1,"uniqueItems":true,"items":{"$ref":"#/components/schemas/JobType"}},"tenureTrack":{"$ref":"#/components/schemas/TenureTrack"},"deadline":{"oneOf":[{"type":"string","format":"date"},{"type":"string","const":""}]},"region":{"$ref":"#/components/schemas/Region"},"submitterAnonymous":{"type":"boolean","default":false}}},"JobListResponse":{"type":"object","additionalProperties":false,"required":["jobs","count"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"count":{"type":"integer","minimum":0}}},"JobSubmissionResponse":{"type":"object","additionalProperties":false,"required":["job"],"properties":{"job":{"$ref":"#/components/schemas/SubmittedJob"}}},"SubmittedJob":{"allOf":[{"$ref":"#/components/schemas/Job"},{"type":"object","required":["submissionPermalink"]}]},"JobResponse":{"type":"object","additionalProperties":false,"required":["job"],"properties":{"job":{"$ref":"#/components/schemas/Job"}}},"ApplicationJobSummary":{"type":"object","additionalProperties":false,"required":["slug","positionName","university","region","status"],"properties":{"slug":{"type":"string"},"positionName":{"type":"string"},"university":{"type":"string"},"region":{"$ref":"#/components/schemas/Region"},"status":{"$ref":"#/components/schemas/JobStatus"}}},"Application":{"type":"object","additionalProperties":false,"required":["id","userId","jobId","externalTitle","externalOrganization","externalUrl","status","priority","deadline","notes","permalink","jobPermalink","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"jobId":{"oneOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"externalTitle":{"type":"string","maxLength":200},"externalOrganization":{"type":"string","maxLength":200},"externalUrl":{"oneOf":[{"type":"string","format":"uri","maxLength":2048,"pattern":"^https?://"},{"type":"string","const":""}]},"status":{"$ref":"#/components/schemas/ApplicationStatus"},"priority":{"$ref":"#/components/schemas/ApplicationPriority"},"deadline":{"oneOf":[{"type":"string","format":"date"},{"type":"string","const":""}]},"notes":{"type":"string","maxLength":5000},"permalink":{"type":"string","format":"uri","description":"Authenticated IS Jobs dashboard page for this tracker application."},"jobPermalink":{"description":"Public IS Jobs page for a published linked job, or null for an external opportunity or non-public job.","oneOf":[{"type":"string","format":"uri"},{"type":"null"}]},"job":{"oneOf":[{"$ref":"#/components/schemas/ApplicationJobSummary"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ApplicationCreateRequest":{"type":"object","additionalProperties":false,"oneOf":[{"required":["jobId"],"not":{"anyOf":[{"required":["externalTitle"]},{"required":["externalOrganization"]},{"required":["externalUrl"]}]}},{"required":["externalTitle"],"not":{"required":["jobId"]}}],"properties":{"jobId":{"type":"string","format":"uuid"},"externalTitle":{"type":"string","minLength":1,"maxLength":200},"externalOrganization":{"type":"string","maxLength":200},"externalUrl":{"oneOf":[{"type":"string","format":"uri","maxLength":2048,"pattern":"^https?://"},{"type":"string","const":""}]},"status":{"$ref":"#/components/schemas/ApplicationStatus","default":"saved"},"priority":{"$ref":"#/components/schemas/ApplicationPriority","default":"medium"},"deadline":{"oneOf":[{"type":"string","format":"date"},{"type":"string","const":""}]},"notes":{"type":"string","maxLength":5000,"default":""}}},"ApplicationUpdateRequest":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"externalTitle":{"type":"string","minLength":1,"maxLength":200},"externalOrganization":{"type":"string","maxLength":200},"externalUrl":{"oneOf":[{"type":"string","format":"uri","maxLength":2048,"pattern":"^https?://"},{"type":"string","const":""}]},"status":{"$ref":"#/components/schemas/ApplicationStatus"},"priority":{"$ref":"#/components/schemas/ApplicationPriority"},"deadline":{"oneOf":[{"type":"string","format":"date"},{"type":"string","const":""}]},"notes":{"type":"string","maxLength":5000}}},"ApplicationListResponse":{"type":"object","additionalProperties":false,"required":["applications","count"],"properties":{"applications":{"type":"array","items":{"$ref":"#/components/schemas/Application"}},"count":{"type":"integer","minimum":0}}},"ApplicationResponse":{"type":"object","additionalProperties":false,"required":["application"],"properties":{"application":{"$ref":"#/components/schemas/Application"}}},"ApplicationEvent":{"type":"object","additionalProperties":false,"required":["id","applicationId","userId","eventType","body","occurredAt","applicationPermalink"],"properties":{"id":{"type":"string","format":"uuid"},"applicationId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"eventType":{"type":"string","pattern":"^[a-z][a-z0-9_-]*$","maxLength":50},"body":{"type":"string","maxLength":5000},"occurredAt":{"type":"string","format":"date-time"},"applicationPermalink":{"type":"string","format":"uri","description":"Authenticated IS Jobs dashboard page for the parent tracker application."}}},"ApplicationEventCreateRequest":{"type":"object","additionalProperties":false,"required":["body"],"properties":{"eventType":{"type":"string","pattern":"^[a-z][a-z0-9_-]*$","maxLength":50,"default":"note"},"body":{"type":"string","minLength":1,"maxLength":5000},"occurredAt":{"type":"string","format":"date-time"}}},"ApplicationEventListResponse":{"type":"object","additionalProperties":false,"required":["events","count"],"properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/ApplicationEvent"}},"count":{"type":"integer","minimum":0}}},"ApplicationEventResponse":{"type":"object","additionalProperties":false,"required":["event"],"properties":{"event":{"$ref":"#/components/schemas/ApplicationEvent"}}},"ApiTokenCredential":{"type":"object","additionalProperties":false,"required":["id","name","tokenPrefix","tokenKind","scopes","expiresAt","lastUsedAt","revokedAt","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string","minLength":1,"maxLength":100},"tokenPrefix":{"type":"string","description":"Non-secret prefix used to identify the credential."},"tokenKind":{"type":"string","enum":["personal","oauth_access"]},"scopes":{"type":"array","uniqueItems":true,"items":{"$ref":"#/components/schemas/ApiScope"}},"oauthClientId":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource":{"oneOf":[{"type":"string","format":"uri"},{"type":"null"}]},"expiresAt":{"type":"string","format":"date-time"},"lastUsedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"revokedAt":{"oneOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"}}},"ApiTokenCreateRequest":{"type":"object","additionalProperties":false,"required":["name","scopes"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100},"scopes":{"type":"array","minItems":1,"uniqueItems":true,"items":{"$ref":"#/components/schemas/ApiScope"}},"expiresInDays":{"type":"integer","minimum":1,"maximum":365,"default":90}}},"ApiTokenListResponse":{"type":"object","additionalProperties":false,"required":["tokens","count"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/ApiTokenCredential"}},"count":{"type":"integer","minimum":0}}},"ApiTokenCreatedResponse":{"type":"object","additionalProperties":false,"required":["token","credential"],"properties":{"token":{"type":"string","minLength":32,"description":"Raw bearer token. It is shown once and cannot be retrieved later."},"credential":{"$ref":"#/components/schemas/ApiTokenCredential"}}},"OAuthRevocationRequest":{"type":"object","additionalProperties":false,"required":["token","client_id"],"properties":{"token":{"type":"string","minLength":1},"token_type_hint":{"type":"string","enum":["access_token","refresh_token"]},"client_id":{"type":"string"}}},"OAuthTokenRequest":{"oneOf":[{"type":"object","additionalProperties":false,"required":["grant_type","code","client_id","code_verifier"],"properties":{"grant_type":{"type":"string","const":"authorization_code"},"code":{"type":"string"},"client_id":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"code_verifier":{"type":"string","minLength":43,"maxLength":128},"resource":{"type":"string","format":"uri"}}},{"type":"object","additionalProperties":false,"required":["grant_type","refresh_token","client_id"],"properties":{"grant_type":{"type":"string","const":"refresh_token"},"refresh_token":{"type":"string"},"client_id":{"type":"string"},"scope":{"type":"string"},"resource":{"type":"string","format":"uri"}}}]},"OAuthTokenResponse":{"type":"object","additionalProperties":false,"required":["access_token","token_type","expires_in","refresh_token","scope","resource"],"properties":{"access_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","minimum":1},"refresh_token":{"type":"string"},"scope":{"type":"string"},"resource":{"type":"string","format":"uri"}}},"OAuthError":{"type":"object","additionalProperties":false,"required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"},"request_id":{"type":"string","format":"uuid"}}},"OAuthClientRegistrationRequest":{"type":"object","additionalProperties":true,"required":["redirect_uris"],"properties":{"client_name":{"type":"string","minLength":1,"maxLength":100},"scope":{"type":"string"},"redirect_uris":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","format":"uri"}},"token_endpoint_auth_method":{"type":"string","const":"none","default":"none"},"grant_types":{"type":"array","uniqueItems":true,"items":{"type":"string","enum":["authorization_code","refresh_token"]},"default":["authorization_code","refresh_token"]},"response_types":{"type":"array","uniqueItems":true,"items":{"type":"string","enum":["code"]},"default":["code"]}}},"OAuthClientRegistrationResponse":{"type":"object","additionalProperties":false,"required":["client_id","client_id_issued_at","client_name","redirect_uris","token_endpoint_auth_method","grant_types","response_types"],"properties":{"client_id":{"type":"string"},"client_secret":{"type":"string"},"client_id_issued_at":{"type":"integer","minimum":0},"client_secret_expires_at":{"type":"integer","minimum":0,"default":0},"client_name":{"type":"string","minLength":1,"maxLength":100},"redirect_uris":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","format":"uri"}},"token_endpoint_auth_method":{"type":"string","const":"none"},"grant_types":{"type":"array","uniqueItems":true,"items":{"type":"string","enum":["authorization_code","refresh_token"]}},"response_types":{"type":"array","uniqueItems":true,"items":{"type":"string","enum":["code"]}},"scope":{"type":"string"}}},"JsonRpcRequest":{"type":"object","required":["jsonrpc","method"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"method":{"type":"string","minLength":1},"params":{"type":"object","additionalProperties":true}}},"McpRequest":{"oneOf":[{"$ref":"#/components/schemas/JsonRpcRequest"},{"type":"array","minItems":1,"maxItems":10,"description":"Legacy MCP protocol batches only; current protocol versions reject arrays.","items":{"$ref":"#/components/schemas/JsonRpcRequest"}}]},"JsonRpcResponse":{"oneOf":[{"$ref":"#/components/schemas/JsonRpcSuccessResponse"},{"$ref":"#/components/schemas/JsonRpcErrorResponse"}]},"McpResponse":{"oneOf":[{"$ref":"#/components/schemas/JsonRpcResponse"},{"type":"array","minItems":1,"maxItems":10,"description":"Legacy MCP batch response.","items":{"$ref":"#/components/schemas/JsonRpcResponse"}}]},"JsonRpcSuccessResponse":{"type":"object","additionalProperties":false,"required":["jsonrpc","id","result"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"result":{"type":"object","additionalProperties":true}}},"JsonRpcErrorResponse":{"type":"object","additionalProperties":false,"required":["jsonrpc","id","error"],"properties":{"jsonrpc":{"type":"string","const":"2.0"},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{}}}}}}}}