Falaah Falaah AI

Documents API

Upload, list, read, update, delete, download and search documents with the Muin REST API: endpoints, parameters, example requests and responses, and errors.

The Documents API lets your own code put files into Muin’s document library and read them back, including the data Muin extracts from each file.

When you’d use this

  • Send scanned receipts or invoices from another system into Muin for extraction.
  • Pull a list of new documents, with their extracted data, into a report or spreadsheet.
  • Tag or reclassify documents in bulk from a script.
  • Search the text of your documents from an external tool.

Before you start

Item Value
Base URL https://muin-api.falaah.ai/api/v1
Header Authorization: Bearer muin_<64 hex characters>
Read endpoints (GET) A key with the Read or Write scope
POST, PATCH, DELETE A key with the Write scope
Module access The person who created the key needs access to the Documents module. The key acts with that person’s role.

How to create a key, the scopes, and the daily request limit: Authentication.

The examples below read the key from an environment variable:

export MUIN_API_KEY="muin_your_api_key_here"

Endpoints

Action Request
Upload a document POST /api/v1/documents/upload
List documents GET /api/v1/documents/
Get one document GET /api/v1/documents/{document_id}
Update a document PATCH /api/v1/documents/{document_id}
Delete a document DELETE /api/v1/documents/{document_id}
Get a download link GET /api/v1/documents/{document_id}/download
Search document text POST /api/v1/documents/search

Upload a document

POST /api/v1/documents/upload
Content-Type: multipart/form-data
Field Type Required Description
file file Yes The file. Up to 50 MB. Empty files are refused.
document_type string No A document type key such as invoice. Leave it out and Muin classifies the file during processing.

Accepted file types: PDF, DOC, DOCX, XLS, XLSX, ODT, ODS, ODP, CSV, TXT, MD, RTF, JPG, JPEG, PNG, GIF, WEBP, BMP, TIFF, SVG and HEIC.

Muin checks the file type from the Content-Type of the file part, and checks that the file’s content matches it. Set the type explicitly in curl with ;type=... so it is not sent as application/octet-stream.

Uploads are limited to 30 per hour per user. Each upload also counts against your plan’s document and storage limits.

curl -X POST https://muin-api.falaah.ai/api/v1/documents/upload \
  -H "Authorization: Bearer $MUIN_API_KEY" \
  -F "file=@invoice-1042.pdf;type=application/pdf" \
  -F "document_type=invoice"

Response (201 Created):

{
  "id": "3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31",
  "filename": "invoice-1042.pdf",
  "status": "pending",
  "message": "Document uploaded successfully"
}

Knowing when processing is done

Processing runs in the background after the upload returns. Read the document’s status with Get one document, or subscribe to the document.processed webhook instead of polling.

status Meaning
pending Uploaded, not yet picked up for processing
processing Muin is extracting data. Also shown while a failed extraction is being retried automatically.
ready Processing finished. extracted_data is filled in.
review_needed Processing finished, but Muin’s classification has low confidence and a person should check it
reviewed A person confirmed the classification
extraction_failed Extraction failed and all automatic retries are used up
error Processing failed. See error_message.

Processing is done once status is anything other than pending or processing.


List documents

GET /api/v1/documents/

Returns the documents in your organization, 20 per page by default, newest first unless you set sort_by.

Parameter Type Required Description
page integer No Page number, starting at 1. Default 1.
page_size integer No Items per page, 1 to 100. Default 20. (per_page is accepted as an alias.)
status string No Processing status. Comma-separated for several, for example ready,review_needed.
document_type string No Document type key. Comma-separated for several.
module string No Business module, for example finance. Comma-separated for several.
business_status string No Workflow status, for example pending_review or approved. Comma-separated for several.
ai_audience string No none, internal or public. Who the AI assistant may quote the document to.
uploaded_by UUID No Only documents uploaded by this user.
tags string No Comma-separated tags. A document must have all of them.
date_from date No Created on or after this date (YYYY-MM-DD).
date_to date No Created on or before this date (YYYY-MM-DD).
origin string No uploaded, template, composer, connector or all.
filter string No Free-text match on filename, type, tags, notes, extracted data and document text.
sort_by string No name, created_at, updated_at, module, document_type or file_size.
sort_order string No asc or desc.
curl "https://muin-api.falaah.ai/api/v1/documents/?status=ready&document_type=invoice&page_size=50" \
  -H "Authorization: Bearer $MUIN_API_KEY"

Response (trimmed to one document):

{
  "documents": [
    {
      "id": "3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31",
      "filename": "invoice-1042.pdf",
      "original_filename": "invoice-1042.pdf",
      "mime_type": "application/pdf",
      "file_size": 184233,
      "status": "ready",
      "document_type": "invoice",
      "module": "finance",
      "tags": ["utilities"],
      "created_at": "2026-10-05T17:30:28Z",
      "updated_at": "2026-10-05T17:31:02Z"
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 50,
  "total_pages": 1,
  "has_more": false,
  "total_unfiltered": null
}

Each item in documents has the same fields as Get one document. Keep requesting the next page while has_more is true.


Get one document

GET /api/v1/documents/{document_id}
Parameter Type Required Description
document_id UUID (path) Yes The document’s id.
curl https://muin-api.falaah.ai/api/v1/documents/3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31 \
  -H "Authorization: Bearer $MUIN_API_KEY"

Response (trimmed):

{
  "id": "3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31",
  "filename": "invoice-1042.pdf",
  "original_filename": "invoice-1042.pdf",
  "mime_type": "application/pdf",
  "file_size": 184233,
  "status": "ready",
  "document_type": "invoice",
  "module": "finance",
  "extracted_data": {
    "vendor_name": "City Water Utility",
    "total_amount": 412.5,
    "invoice_date": "2026-09-28"
  },
  "tags": ["utilities"],
  "notes": null,
  "ai_audience": "internal",
  "extraction_quality": 0.93,
  "error_message": null,
  "business_status": "pending_review",
  "business_status_updated_at": "2026-10-05T17:31:02Z",
  "workflow_instance_id": null,
  "created_at": "2026-10-05T17:30:28Z",
  "updated_at": "2026-10-05T17:31:02Z",
  "uploaded_by": {
    "id": "a1d4b7c2-0e5f-4a83-9c61-7b2e8f3d1a90",
    "name": "Aisha Rahman"
  },
  "source_template_id": null,
  "source_assembly_project_id": null,
  "source_connector_id": null,
  "source_assembly_project": null
}
Field Description
status Processing status (see the table under Upload).
extracted_data The structured data Muin extracted. Its keys depend on the document type.
extraction_quality Confidence from 0.0 to 1.0. null until processed.
error_message Why processing failed. null on success.
business_status Workflow status, for example pending_review, approved, rejected or paid.
uploaded_by The uploader. null for documents created by the system or a connector.
source_template_id, source_assembly_project_id, source_connector_id Set when the document came from a template, the document composer, or a cloud connector.

Update a document

PATCH /api/v1/documents/{document_id}
Content-Type: application/json

Changes the document’s details, not the file. Send only the fields you want to change. Only the uploader, someone the document is shared with for editing, or an owner or admin can update it.

Field Type Required Description
document_type string No A registered document type key, for example invoice. Unknown keys are refused.
module string No Business module, for example finance.
tags array of strings No Replaces the document’s tags.
notes string No Up to 2,000 characters.
extracted_data object No Corrected extracted data.
ai_audience string No none, internal or public. public lets the AI assistant quote this document to anyone, including visitors who are not signed in.
curl -X PATCH https://muin-api.falaah.ai/api/v1/documents/3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31 \
  -H "Authorization: Bearer $MUIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tags": ["utilities", "fy2026"],
    "notes": "Paid by check 2214"
  }'

The response is the full updated document, in the same shape as Get one document.


Delete a document

DELETE /api/v1/documents/{document_id}

Only the uploader or an owner or admin can delete a document. Muin marks the record as deleted (it no longer appears in lists or lookups) and removes the file from storage. Any signature requests still open on the document are voided.

Parameter Type Required Description
document_id UUID (path) Yes The document’s id.
curl -X DELETE https://muin-api.falaah.ai/api/v1/documents/3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31 \
  -H "Authorization: Bearer $MUIN_API_KEY"

Response:

{
  "message": "Document deleted successfully"
}

Download a document

GET /api/v1/documents/{document_id}/download

Returns a signed link to the original file. It does not return the file itself.

Parameter Type Required Description
document_id UUID (path) Yes The document’s id.
expires integer (query) No Seconds the link stays valid, 60 to 86,400. Default 3600.
intent string (query) No preview (default) or download. download records the download in the audit log.
curl "https://muin-api.falaah.ai/api/v1/documents/3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31/download?expires=600&intent=download" \
  -H "Authorization: Bearer $MUIN_API_KEY"

Response:

{
  "url": "https://.../invoice-1042.pdf?...",
  "expires_in": 600
}

Fetch url before it expires. The link is signed, so it does not need the Authorization header:

curl -o invoice-1042.pdf "<url from the response>"

Search document text

POST /api/v1/documents/search
Content-Type: application/json

Finds passages in your documents that are close in meaning to your query. Results only include documents from modules the key’s creator can view. This is a POST, so it needs a key with the Write scope even though it changes nothing.

Field Type Required Description
query string Yes What to look for, 1 to 1,000 characters.
limit integer No Maximum results, 1 to 50. Default 10.
threshold number No Minimum similarity, 0.0 to 1.0. Default 0.7. Lower it to get more, looser matches.
curl -X POST https://muin-api.falaah.ai/api/v1/documents/search \
  -H "Authorization: Bearer $MUIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "water bill for September",
    "limit": 5
  }'

Response:

{
  "query": "water bill for September",
  "results": [
    {
      "document_id": "3f6c1e8a-9b2d-4c7e-8f10-5a2b7d9e4c31",
      "document_filename": "invoice-1042.pdf",
      "chunk_index": 0,
      "content": "City Water Utility. Service period September 1 to September 30...",
      "similarity": 0.84
    }
  ],
  "total": 1
}

Only processed documents can be found. A document still in pending or processing has no searchable text yet.


When it goes wrong

Errors from these endpoints return a JSON body with an error object holding code, message and status. Request-format errors (422 from a bad parameter) list the field that failed.

Status Why What to do
400 The uploaded file is empty. Send a file with content.
401 The key is missing, wrong, revoked or expired. See Authentication.
403 The key has only Read scope and you sent POST, PATCH or DELETE. Use a key with Write.
403 The key’s creator has no access to the Documents module, or is not allowed to edit or delete this document. Create the key as an owner or admin, or as someone with access to the document.
403 Your plan’s document or storage limit is reached. Delete documents or upgrade your plan.
404 No document with that id in your organization, or it was deleted. Check the id with List documents.
422 Upload: unsupported file type, file over 50 MB, or the content does not match the declared type. Send an accepted type with the correct type= in the file part.
422 A parameter or body field is invalid, for example a malformed UUID, an unknown document_type on update, or page_size over 100. Fix the field named in the error.
429 More than 30 uploads in an hour, too many searches in a short time, or your plan’s daily request limit is reached. Wait and retry. For the daily limit, see Authentication.

Next step

  • Authentication: create the API key these calls need, and choose its scope.
  • Webhooks: get a document.processed event instead of polling for status.