{"openapi":"3.1.0","info":{"title":"MARK API","description":"The MARK API allows you to programmatically manage your knowledge bases and documents.\n\n## Authentication\n\nAll requests require an API key passed via the `X-API-Key` header:\n\n```\nX-API-Key: mk_live_a8f3x9k2m4pQb7n4p1q8r3wZ\n```\n\nGenerate API keys from your workspace settings. The full key is shown only once at creation — store it securely.","version":"1.0.0","contact":{"name":"MARK Support","url":"https://markcopy.ai"}},"servers":[{"url":"https://api.markcopy.ai/api/v1","description":"Production"}],"security":[{"apiKey":[]}],"paths":{"/knowledge-bases":{"get":{"operationId":"listKnowledgeBases","summary":"List knowledge bases","description":"Returns all knowledge bases accessible with this API key.","tags":["Knowledge Base"],"responses":{"200":{"description":"List of knowledge bases.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"External ID of the knowledge base (prefixed with `kb_`).","example":"kb_a8f3x9k2m4pQ"},"name":{"type":"string","description":"Name of the knowledge base.","example":"default"},"workspace":{"type":"string","description":"Name of the workspace.","example":"Marketing Team"}}}}}},"example":{"items":[{"id":"kb_a8f3x9k2m4pQ","name":"default","workspace":"Marketing Team"}]}}}}}}},"/knowledge-bases/{id}/tags":{"get":{"operationId":"listTags","summary":"List tags","description":"Returns all tags for a knowledge base, with the number of documents associated with each tag.","tags":["Knowledge Base"],"parameters":[{"name":"id","in":"path","required":true,"description":"The external ID of the knowledge base (prefixed with `kb_`).","schema":{"type":"string","example":"kb_a8f3x9k2m4pQ"}}],"responses":{"200":{"description":"List of tags.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Tag name.","example":"reports"},"createdAt":{"type":"string","format":"date-time"},"documentCount":{"type":"integer","description":"Number of documents with this tag.","example":12}}}}}},"example":{"items":[{"name":"guidelines","createdAt":"2026-03-18T10:30:00.000Z","documentCount":3},{"name":"reports","createdAt":"2026-03-19T08:00:00.000Z","documentCount":12}]}}}},"404":{"description":"Knowledge base not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/knowledge-bases/{id}/documents":{"post":{"operationId":"uploadDocument","summary":"Upload a document","description":"Upload a document to a knowledge base by providing a URL (web page or file) or raw text content. The document is processed asynchronously — the response confirms the document was accepted and queued for processing.\n\nWhen uploading raw text that you've already extracted yourself (for example, from an internal wiki or an auth-gated page), you can optionally pass `sourceUrl` to record the original URL as the document's source for retrieval and citation.\n\n**Supported file formats:** PDF, DOCX, DOC, TXT, CSV, XLSX, XLS, PPTX, PPT, MP3, WAV, OGG, M4A, WEBM, PNG, JPG, JPEG, GIF, WEBP","tags":["Knowledge Base"],"parameters":[{"name":"id","in":"path","required":true,"description":"The external ID of the knowledge base (prefixed with `kb_`).","schema":{"type":"string","example":"kb_a8f3x9k2m4pQ"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"URL of a web page or file to import. Mutually exclusive with `text`.","example":"https://example.com/report.pdf"},"text":{"type":"string","description":"Raw text content to store. Mutually exclusive with `url`.","example":"Our company was founded in 2020..."},"name":{"type":"string","maxLength":255,"description":"Human-readable name for the document. If omitted, a name is derived from the URL or a default is used.","example":"Q4 2025 Report"},"tags":{"type":"array","items":{"type":"string"},"description":"Tags to associate with the document. Tags are created automatically if they don't exist.","example":["reports","quarterly"]},"sourceUrl":{"type":"string","format":"uri","description":"Optional. Original URL the text was extracted from, recorded as the document's source for retrieval and citation. Only valid alongside `text` — sending it with `url` returns `invalid_parameters`. Must be a valid HTTP or HTTPS URL.","example":"https://wiki.internal/page-1"},"mimeType":{"type":"string","enum":["text/markdown","text/plain","text/html","application/json"],"description":"Optional. Declares the format of the provided `text` (markdown, plain text, HTML, or JSON). Only valid alongside `text` — sending it with `url` returns `invalid_parameters` (the content type is detected automatically when fetching a URL).","example":"text/markdown"}}},"examples":{"url-web":{"summary":"Import a web page","value":{"url":"https://example.com/about","name":"About Page","tags":["website"]}},"url-file":{"summary":"Import a PDF file","value":{"url":"https://example.com/report.pdf","name":"Annual Report"}},"text":{"summary":"Upload raw text","value":{"text":"Our brand voice is professional yet approachable. We avoid jargon and write in short, clear sentences.","name":"Brand Voice Guidelines","tags":["brand","guidelines"]}},"text-with-source":{"summary":"Upload pre-extracted text with a source URL","value":{"text":"Our internal onboarding guide covers the first 30 days of any new role.","name":"Onboarding Guide","tags":["handbook"],"sourceUrl":"https://wiki.internal/handbook/onboarding"}}}}}},"responses":{"201":{"description":"Document accepted and queued for processing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"},"example":{"id":"doc_b7n4p1q8r3wX","status":"processing","name":"Q4 2025 Report","sourceType":"url","tags":["reports","quarterly"],"createdAt":"2026-03-18T10:30:00.000Z"}}}},"400":{"description":"Invalid or missing parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_parameters","message":"Exactly one of \"url\" or \"text\" must be provided.","status":400}}}}},"401":{"description":"API key is missing, invalid, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_api_key","message":"The provided API key is invalid.","status":401}}}}},"403":{"description":"Plan does not include API access or key lacks required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"api_access_denied","message":"Your current plan does not include API access.","status":403}}}}},"404":{"description":"Knowledge base not found or not accessible with this API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"knowledge_base_not_found","message":"The knowledge base 'kb_abc123' was not found or is not accessible with this API key.","status":404}}}}},"409":{"description":"A document with the same URL already exists in this knowledge base.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"duplicate_document","message":"A document with this URL already exists in the knowledge base.","status":409}}}}},"422":{"description":"The file URL points to an unsupported format.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unsupported_format","message":"The file format \".exe\" is not supported.","status":422}}}}},"429":{"description":"Rate limit or monthly quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limit_exceeded","message":"Monthly document upload limit reached: 500 used out of 500.","status":429}}}},"headers":{"Retry-After":{"description":"Seconds until the rate limit resets.","schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"internal_error","message":"An unexpected error occurred.","status":500}}}}}}}},"/knowledge-bases/{id}/documents/batch":{"post":{"operationId":"uploadDocumentsBatch","summary":"Upload multiple documents","description":"Upload up to 100 documents to a knowledge base in a single request. Each document is processed independently — the response includes per-item results so you can identify which succeeded and which failed.\n\nEach item supports the same fields as the single-upload endpoint, including the optional `sourceUrl` field on `text` uploads.","tags":["Knowledge Base"],"parameters":[{"name":"id","in":"path","required":true,"description":"The external ID of the knowledge base (prefixed with `kb_`).","schema":{"type":"string","example":"kb_a8f3x9k2m4pQ"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["documents"],"properties":{"documents":{"type":"array","maxItems":100,"items":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"URL of a web page or file to import. Mutually exclusive with `text`."},"text":{"type":"string","description":"Raw text content to store. Mutually exclusive with `url`."},"name":{"type":"string","maxLength":255,"description":"Human-readable name for the document."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags to associate with the document."},"sourceUrl":{"type":"string","format":"uri","description":"Optional. Original URL the text was extracted from. Only valid alongside `text`."},"mimeType":{"type":"string","enum":["text/markdown","text/plain","text/html","application/json"],"description":"Optional. Declares the format of the provided `text`. Only valid alongside `text`."}}}}}},"example":{"documents":[{"url":"https://example.com/about","name":"About Page"},{"url":"https://example.com/report.pdf","name":"Annual Report","tags":["reports"]},{"text":"Our brand voice is professional yet approachable.","name":"Brand Voice"},{"text":"Our internal onboarding guide covers the first 30 days.","name":"Onboarding Guide","sourceUrl":"https://wiki.internal/handbook/onboarding"}]}}}},"responses":{"200":{"description":"Batch processed. Each item has its own success or error status.","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"status":{"type":"string","enum":["success"]},"document":{"$ref":"#/components/schemas/Document"}}},{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}]}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"}}}}},"example":{"results":[{"status":"success","document":{"id":"doc_a1b2c3d4e5fG","status":"processing","name":"About Page","sourceType":"url","tags":[],"createdAt":"2026-03-18T10:30:00.000Z"}},{"status":"success","document":{"id":"doc_h6i7j8k9l0mN","status":"processing","name":"Annual Report","sourceType":"url","tags":["reports"],"createdAt":"2026-03-18T10:30:00.000Z"}},{"status":"error","error":{"code":"duplicate_document","message":"A document with this URL already exists in the knowledge base."}}],"summary":{"total":3,"succeeded":2,"failed":1}}}}},"400":{"description":"Invalid request body (not an array, empty, or exceeds batch size).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key is missing, invalid, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Knowledge base not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Monthly quota exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateDocumentsBatch","summary":"Update multiple documents","description":"Update metadata (`sourceUrl`, `name`, `tags`) of up to 100 existing documents in a single request, without re-uploading their content. Each item must include the document `id`. Items are processed independently — the response includes per-item results.","tags":["Knowledge Base"],"parameters":[{"name":"id","in":"path","required":true,"description":"The external ID of the knowledge base (prefixed with `kb_`).","schema":{"type":"string","example":"kb_a8f3x9k2m4pQ"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["documents"],"properties":{"documents":{"type":"array","maxItems":100,"items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The external ID of the document to update (prefixed with `doc_`)."},"sourceUrl":{"type":"string","format":"uri","description":"New source URL. Must be a valid HTTP or HTTPS URL."},"name":{"type":"string","maxLength":255,"description":"New name for the document."},"tags":{"type":"array","items":{"type":"string"},"description":"Replaces the document's tags with this set. Tags are created automatically if they don't exist."},"mimeType":{"type":"string","enum":["text/markdown","text/plain","text/html","application/json"],"description":"New declared format for the document."}}}}}},"example":{"documents":[{"id":"doc_b7n4p1q8r3wX","sourceUrl":"https://wiki.internal/handbook/onboarding"},{"id":"doc_c8m5q2r9s4xY","name":"Updated Name","tags":["handbook","hr"],"mimeType":"text/markdown"}]}}}},"responses":{"200":{"description":"Batch processed. Each item has its own success or error status.","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"status":{"type":"string","enum":["success"]},"document":{"$ref":"#/components/schemas/UpdatedDocument"}}},{"type":"object","properties":{"status":{"type":"string","enum":["error"]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}]}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"succeeded":{"type":"integer"},"failed":{"type":"integer"}}}}}}}},"400":{"description":"Invalid or missing parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"API key is missing, invalid, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/knowledge-bases/{id}/documents/{documentId}":{"patch":{"operationId":"updateDocument","summary":"Update a document","description":"Update metadata (`sourceUrl`, `name`, `tags`) of an existing document without re-uploading its content. At least one field must be provided. Updating `tags` replaces the document's existing tags with the provided set.","tags":["Knowledge Base"],"parameters":[{"name":"id","in":"path","required":true,"description":"The external ID of the knowledge base (prefixed with `kb_`).","schema":{"type":"string","example":"kb_a8f3x9k2m4pQ"}},{"name":"documentId","in":"path","required":true,"description":"The external ID of the document (prefixed with `doc_`).","schema":{"type":"string","example":"doc_b7n4p1q8r3wX"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"sourceUrl":{"type":"string","format":"uri","description":"New source URL for the document, used as the citation source in retrieval. Must be a valid HTTP or HTTPS URL."},"name":{"type":"string","maxLength":255,"description":"New name for the document."},"tags":{"type":"array","items":{"type":"string"},"description":"Replaces the document's tags with this set. Tags are created automatically if they don't exist."},"mimeType":{"type":"string","enum":["text/markdown","text/plain","text/html","application/json"],"description":"New declared format for the document (markdown, plain text, HTML, or JSON)."}}},"examples":{"set-source":{"summary":"Backfill a source URL","value":{"sourceUrl":"https://wiki.internal/handbook/onboarding"}},"rename-and-retag":{"summary":"Rename and replace tags","value":{"name":"Onboarding Guide","tags":["handbook","hr"]}},"set-format":{"summary":"Set the declared format","value":{"mimeType":"text/markdown"}}}}}},"responses":{"200":{"description":"Document updated.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatedDocument"},"example":{"id":"doc_b7n4p1q8r3wX","name":"Onboarding Guide","sourceUrl":"https://wiki.internal/handbook/onboarding","tags":["handbook","hr"],"updatedAt":"2026-06-01T10:30:00.000Z"}}}},"400":{"description":"Invalid or missing parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_parameters","message":"At least one of \"sourceUrl\", \"name\", \"tags\", or \"mimeType\" must be provided.","status":400}}}}},"401":{"description":"API key is missing, invalid, or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Document not found or not accessible with this API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"The document 'doc_b7n4p1q8r3wX' was not found or is not accessible with this API key.","status":404}}}}}}}},"/jobs/{jobId}":{"get":{"operationId":"getJob","summary":"Get job status","description":"Check the processing status of a document upload job. Jobs are retained for 90 days.","tags":["Jobs"],"parameters":[{"name":"jobId","in":"path","required":true,"description":"The job ID returned when uploading a document (prefixed with `job_`).","schema":{"type":"string","example":"job_a8f3x9k2m4pQ"}}],"responses":{"200":{"description":"Job details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"},"examples":{"completed":{"summary":"Completed job","value":{"jobId":"job_a8f3x9k2m4pQ","batchId":null,"type":"knowledge-document-upload","status":"completed","input":{"url":"https://example.com/report.pdf","name":"Annual Report"},"result":{"documentId":"doc_b7n4p1q8r3wX"},"createdAt":"2026-03-18T10:30:00.000Z","updatedAt":"2026-03-18T10:31:15.000Z"}},"failed":{"summary":"Failed job","value":{"jobId":"job_a8f3x9k2m4pQ","batchId":null,"type":"knowledge-document-upload","status":"failed","input":{"url":"https://example.com/broken.pdf","name":"Broken File"},"result":{"errorCode":"extraction_failed","errorMessage":"Text extraction failed for the uploaded file."},"createdAt":"2026-03-18T10:30:00.000Z","updatedAt":"2026-03-18T10:31:15.000Z"}}}}}},"404":{"description":"Job not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/batches/{batchId}":{"get":{"operationId":"getBatch","summary":"Get batch status","description":"Check the processing status of a batch upload. Returns all jobs in the batch with a summary of completed, failed, and pending counts.","tags":["Jobs"],"parameters":[{"name":"batchId","in":"path","required":true,"description":"The batch ID returned from the batch upload endpoint (prefixed with `batch_`).","schema":{"type":"string","example":"batch_x7y8z9w0v1uT"}}],"responses":{"200":{"description":"Batch details with all jobs.","content":{"application/json":{"schema":{"type":"object","properties":{"batchId":{"type":"string"},"status":{"type":"string","enum":["processing","completed"],"description":"`processing` if any jobs are still pending, `completed` when all jobs have finished."},"summary":{"type":"object","properties":{"total":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"},"pending":{"type":"integer"}}},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/Job"}}}},"example":{"batchId":"batch_x7y8z9w0v1uT","status":"completed","summary":{"total":3,"completed":2,"failed":1,"pending":0},"jobs":[{"jobId":"job_a1b2c3d4e5fG","type":"knowledge-document-upload","status":"completed","input":{"url":"https://example.com/about"},"result":{"documentId":"doc_h6i7j8k9l0mN"},"createdAt":"2026-03-18T10:30:00.000Z","updatedAt":"2026-03-18T10:31:00.000Z"},{"jobId":"job_p2q3r4s5t6uV","type":"knowledge-document-upload","status":"completed","input":{"url":"https://example.com/report.pdf","name":"Annual Report"},"result":{"documentId":"doc_w7x8y9z0a1bC"},"createdAt":"2026-03-18T10:30:00.000Z","updatedAt":"2026-03-18T10:32:00.000Z"},{"jobId":"job_d3e4f5g6h7iJ","type":"knowledge-document-upload","status":"failed","input":{"url":"https://example.com/broken.pdf"},"result":{"errorCode":"extraction_failed","errorMessage":"Text extraction failed for the uploaded file."},"createdAt":"2026-03-18T10:30:00.000Z","updatedAt":"2026-03-18T10:31:30.000Z"}]}}}},"404":{"description":"Batch not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Pass your API key in the `X-API-Key` header. Example: `mk_live_a8f3x9k2m4pQb7n4p1q8r3wZ`"}},"schemas":{"Document":{"type":"object","properties":{"id":{"type":"string","description":"Unique document ID (prefixed with `doc_`).","example":"doc_b7n4p1q8r3wX"},"jobId":{"type":"string","description":"Job ID for tracking processing status (prefixed with `job_`).","example":"job_a8f3x9k2m4pQ"},"status":{"type":"string","enum":["processing"],"description":"The document processing status. Newly uploaded documents always start as `processing`."},"name":{"type":"string","description":"The document name.","example":"Q4 2025 Report"},"sourceType":{"type":"string","enum":["url","text"],"description":"Whether the document was uploaded via URL or raw text."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags associated with the document.","example":["reports","quarterly"]},"createdAt":{"type":"string","format":"date-time","description":"Timestamp of when the document was created."},"sourceUrl":{"type":"string","format":"uri","description":"Echo of the `sourceUrl` field when one was provided on a text upload. Absent otherwise.","example":"https://wiki.internal/page-1"},"mimeType":{"type":"string","enum":["text/markdown","text/plain","text/html","application/json"],"description":"Echo of the `mimeType` field when one was provided on a text upload. Absent otherwise.","example":"text/markdown"}}},"UpdatedDocument":{"type":"object","properties":{"id":{"type":"string","description":"Unique document ID (prefixed with `doc_`).","example":"doc_b7n4p1q8r3wX"},"name":{"type":"string","description":"The document name after the update.","example":"Onboarding Guide"},"sourceUrl":{"type":"string","format":"uri","description":"The new source URL, present only when `sourceUrl` was updated.","example":"https://wiki.internal/handbook/onboarding"},"tags":{"type":"array","items":{"type":"string"},"description":"The document's tags after the update, present only when `tags` was updated.","example":["handbook","hr"]},"mimeType":{"type":"string","enum":["text/markdown","text/plain","text/html","application/json"],"description":"The document's declared format after the update, present only when `mimeType` was updated.","example":"text/markdown"},"updatedAt":{"type":"string","format":"date-time","description":"Timestamp of when the document was last updated."}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Machine-readable error code."},"message":{"type":"string","description":"Human-readable error description."},"status":{"type":"integer","description":"HTTP status code."}}}}},"Job":{"type":"object","properties":{"jobId":{"type":"string","description":"Unique job ID (prefixed with `job_`).","example":"job_a8f3x9k2m4pQ"},"batchId":{"type":"string","nullable":true,"description":"Batch ID if this job was part of a batch upload.","example":"batch_x7y8z9w0v1uT"},"type":{"type":"string","description":"The type of job.","example":"knowledge-document-upload"},"status":{"type":"string","enum":["queued","processing","completed","failed"],"description":"Current processing status."},"input":{"type":"object","description":"The original input provided when creating the job.","properties":{"url":{"type":"string"},"text":{"type":"string"},"name":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"result":{"type":"object","nullable":true,"description":"Result details. Contains `documentId` on success, or `errorCode` and `errorMessage` on failure.","properties":{"documentId":{"type":"string"},"errorCode":{"type":"string"},"errorMessage":{"type":"string"}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}