> ## Documentation Index
> Fetch the complete documentation index at: https://docs.melso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Melso product MCP: https://melso.ai/api/mcp (OAuth; one company per grant). REST: https://melso.ai. Documentation-search MCP: https://docs.melso.ai/mcp. The docs search server does not act on customer accounts.
>
> Use the live tool schema and respect company membership. Ask the person to authorize the exact fiscal document version in the signed-in app. A professional prepares and files included returns after authorization; AI does not file alone. A prepared file or approval receipt is not evidence of filing. Never claim completion from an accepted Task or Run. Keep credentials out of chat and logs. Agents features are internal or by private invitation.

# expenses

> Input, output and examples for the expenses MCP tool.

Read and record this company's expenses, and read any invoice or receipt with from\_document, which records it as an expense or an income. Monetary amounts are EUR decimal strings. update requires the saved expected\_version, preserves fiscal evidence rules and invalidates any prior owner review. Deductible is a classification, not approval of a deduction. category is the AEAT expense concept code; deductibility is Melso's estimate (likely, review or unlikely) with the rule behind it, never a confirmed deduction. Each action accepts only its own fields (\* required): list; get(id\*); create(supplier\_name\*, date\*, subtotal\*, vat\_amount\*, total\*, attachment\_id, category, deductible, document\_number, file\_id, irpf\_amount, irpf\_rate, source, supplier\_country, supplier\_tax\_id, vat\_rate, vat\_treatment); from\_document(attachment\_id, counterparty\_country, direction, file\_id, filename, upload\_id, url); document\_status(job\_id); update(id\*, expected\_version\*, attachment\_id, category, date, deductible, document\_number, file\_id, irpf\_amount, irpf\_rate, subtotal, supplier\_country, supplier\_name, supplier\_tax\_id, total, vat\_amount, vat\_rate, vat\_treatment); upload(filename\*, content\_type\*, size\_bytes\*); delete(id\*).

**Availability:** Autónomo / Empresa.

**Catalog:** Core (`tools/list`).

The live catalog is authoritative: company type, membership, plan, connected apps and execution context can narrow this contract. [Understand access](/mcp/permissions).

## Input

### Autónomo / Company schema

```json theme={null}
{
  "additionalProperties": false,
  "properties": {
    "action": {
      "enum": [
        "list",
        "get",
        "create",
        "from_document",
        "document_status",
        "update",
        "upload",
        "delete"
      ],
      "type": "string"
    },
    "attachment_id": {
      "description": "A photo or file the person sent in this chat, by its attachment_id. It is stored in their Documents as the expense's evidence; use it instead of file_id.",
      "type": "string"
    },
    "category": {
      "description": "The AEAT expense concept code of the libro registro de gastos (for example G22 Otros servicios exteriores, G17 telefonía e internet, G45 cuota de autónomo), or null for none. Never guess it: leave it out when unsure. Setting it marks a category Melso proposed as reviewed.",
      "enum": [
        "G01",
        "G02",
        "G03",
        "G04",
        "G05",
        "G45",
        "G46",
        "G07",
        "G08",
        "G09",
        "G10",
        "G11",
        "G12",
        "G13",
        "G14",
        "G15",
        "G16",
        "G17",
        "G18",
        "G19",
        "G40",
        "G41",
        "G42",
        "G20",
        "G22",
        "G44",
        "G23",
        "G24",
        "G25",
        "G26",
        "G27",
        "G28",
        "G29",
        "G30",
        "G31",
        "G32",
        "G33",
        "G38",
        "G34",
        "G35",
        "G36",
        "G43",
        "G37",
        "G39",
        "G47",
        null
      ],
      "type": [
        "string",
        "null"
      ]
    },
    "content_type": {
      "description": "The file's type.",
      "enum": [
        "application/pdf",
        "image/jpeg",
        "image/png",
        "image/webp",
        "image/gif"
      ],
      "type": "string"
    },
    "counterparty_country": {
      "description": "Only when known: supplier country for an expense or customer country for income, as a two-letter country code. Use it to answer country_unknown; never assume ES.",
      "type": "string"
    },
    "date": {
      "description": "Expense calendar date YYYY-MM-DD.",
      "type": "string"
    },
    "deductible": {
      "description": "Whether it is a deductible expense of the activity, defaults to unsure. Changing it clears the reason Melso gave.",
      "enum": [
        "yes",
        "no",
        "unsure"
      ],
      "type": "string"
    },
    "direction": {
      "description": "Only when known: income when the company issued the document, expense when it received it.",
      "enum": [
        "income",
        "expense"
      ],
      "type": "string"
    },
    "document_number": {
      "description": "Supplier's original document number.",
      "type": "string"
    },
    "expected_version": {
      "description": "Version from get/list. A stale version is refused.",
      "minimum": 1,
      "type": "integer"
    },
    "file_id": {
      "description": "Readable permanent client Library file UUID for evidence.",
      "type": "string"
    },
    "filename": {
      "description": "Name to store a downloaded document under.",
      "type": "string"
    },
    "id": {
      "description": "Company-scoped expense UUID.",
      "type": "string"
    },
    "irpf_amount": {
      "description": "Nonnegative EUR IRPF withheld on the received invoice as a decimal string.",
      "type": "string"
    },
    "irpf_rate": {
      "description": "IRPF withheld on the received invoice as a 0 to 100 percentage string, empty when none.",
      "type": "string"
    },
    "job_id": {
      "description": "Job from from_document; omit for the latest twenty.",
      "type": "string"
    },
    "size_bytes": {
      "description": "The file's exact size in bytes.",
      "maximum": 15728640,
      "minimum": 1,
      "type": "integer"
    },
    "source": {
      "description": "Intake source, defaults to upload.",
      "enum": [
        "upload",
        "whatsapp",
        "gmail"
      ],
      "type": "string"
    },
    "subtotal": {
      "description": "Nonnegative EUR subtotal as a decimal string.",
      "type": "string"
    },
    "supplier_country": {
      "description": "Supplier country as a two-letter code, defaults to ES.",
      "type": "string"
    },
    "supplier_name": {
      "description": "Supplier name.",
      "type": "string"
    },
    "supplier_tax_id": {
      "description": "Supplier's tax ID.",
      "type": "string"
    },
    "total": {
      "description": "Nonnegative EUR total; must equal subtotal plus vat_amount.",
      "type": "string"
    },
    "upload_id": {
      "description": "The upload_id from upload, once the file was PUT to its upload_url.",
      "type": "string"
    },
    "url": {
      "description": "HTTPS link that downloads the PDF or image, for example from a connected Drive.",
      "type": "string"
    },
    "vat_amount": {
      "description": "Nonnegative EUR VAT as a decimal string.",
      "type": "string"
    },
    "vat_rate": {
      "description": "Applied VAT rate as a 0 to 100 percentage string, empty when unknown. Refused with a non-taxable vat_treatment.",
      "type": "string"
    },
    "vat_treatment": {
      "description": "VAT treatment, defaults to taxable. Non-taxable treatments carry no VAT amount or rate.",
      "enum": [
        "taxable",
        "exempt",
        "reverse_charge",
        "not_subject"
      ],
      "type": "string"
    }
  },
  "required": [
    "action"
  ],
  "type": "object"
}
```

## Actions

The family schema combines fields for discovery. Each action accepts only its own fields below; add `action` when calling the family.

<AccordionGroup>
  <Accordion title="create">
    Record an expense typed by hand with its client-owned evidence. For a photo or PDF use from\_document instead.

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {
        "attachment_id": {
          "description": "A photo or file the person sent in this chat, by its attachment_id. It is stored in their Documents as the expense's evidence; use it instead of file_id.",
          "type": "string"
        },
        "category": {
          "description": "The AEAT expense concept code of the libro registro de gastos (for example G22 Otros servicios exteriores, G17 telefonía e internet, G45 cuota de autónomo), or null for none. Never guess it: leave it out when unsure. Setting it marks a category Melso proposed as reviewed.",
          "enum": [
            "G01",
            "G02",
            "G03",
            "G04",
            "G05",
            "G45",
            "G46",
            "G07",
            "G08",
            "G09",
            "G10",
            "G11",
            "G12",
            "G13",
            "G14",
            "G15",
            "G16",
            "G17",
            "G18",
            "G19",
            "G40",
            "G41",
            "G42",
            "G20",
            "G22",
            "G44",
            "G23",
            "G24",
            "G25",
            "G26",
            "G27",
            "G28",
            "G29",
            "G30",
            "G31",
            "G32",
            "G33",
            "G38",
            "G34",
            "G35",
            "G36",
            "G43",
            "G37",
            "G39",
            "G47",
            null
          ],
          "type": [
            "string",
            "null"
          ]
        },
        "date": {
          "description": "Expense calendar date YYYY-MM-DD.",
          "type": "string"
        },
        "deductible": {
          "description": "Whether it is a deductible expense of the activity, defaults to unsure. Changing it clears the reason Melso gave.",
          "enum": [
            "yes",
            "no",
            "unsure"
          ],
          "type": "string"
        },
        "document_number": {
          "description": "Supplier's original document number.",
          "type": "string"
        },
        "file_id": {
          "description": "Readable permanent client Library file UUID for evidence.",
          "type": "string"
        },
        "irpf_amount": {
          "description": "Nonnegative EUR IRPF withheld on the received invoice as a decimal string.",
          "type": "string"
        },
        "irpf_rate": {
          "description": "IRPF withheld on the received invoice as a 0 to 100 percentage string, empty when none.",
          "type": "string"
        },
        "source": {
          "description": "Intake source, defaults to upload.",
          "enum": [
            "upload",
            "whatsapp",
            "gmail"
          ],
          "type": "string"
        },
        "subtotal": {
          "description": "Nonnegative EUR subtotal as a decimal string.",
          "type": "string"
        },
        "supplier_country": {
          "description": "Supplier country as a two-letter code, defaults to ES.",
          "type": "string"
        },
        "supplier_name": {
          "description": "Supplier name.",
          "type": "string"
        },
        "supplier_tax_id": {
          "description": "Supplier's tax ID.",
          "type": "string"
        },
        "total": {
          "description": "Nonnegative EUR total; must equal subtotal plus vat_amount.",
          "type": "string"
        },
        "vat_amount": {
          "description": "Nonnegative EUR VAT as a decimal string.",
          "type": "string"
        },
        "vat_rate": {
          "description": "Applied VAT rate as a 0 to 100 percentage string, empty when unknown. Refused with a non-taxable vat_treatment.",
          "type": "string"
        },
        "vat_treatment": {
          "description": "VAT treatment, defaults to taxable. Non-taxable treatments carry no VAT amount or rate.",
          "enum": [
            "taxable",
            "exempt",
            "reverse_charge",
            "not_subject"
          ],
          "type": "string"
        }
      },
      "required": [
        "supplier_name",
        "date",
        "subtotal",
        "vat_amount",
        "total"
      ],
      "type": "object"
    }
    ```
  </Accordion>

  <Accordion title="delete">
    Delete an expense recorded by mistake, such as a duplicate, after the person confirms. Its file stays in Documents. Refused when a tax return covering its date was already approved or filed: change it in the web app and file a correction.

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {
        "id": {
          "description": "Company-scoped expense UUID.",
          "type": "string"
        }
      },
      "required": [
        "id"
      ],
      "type": "object"
    }
    ```
  </Accordion>

  <Accordion title="document_status">
    What documents queued with from\_document became: one job by job\_id, or the company's latest twenty. Each says queued, done (with the expense or income recorded, its review codes and deductibility) or failed (with a code; direction\_unknown means ask and queue it again with direction; country\_unknown means ask the supplier/customer country and retry with counterparty\_country and the direction from the error).

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {
        "job_id": {
          "description": "Job from from_document; omit for the latest twenty.",
          "type": "string"
        }
      },
      "type": "object"
    }
    ```
  </Accordion>

  <Accordion title="from_document">
    Read an invoice or receipt (PDF or photo) and record it: as an expense when the company received it, as income when it issued it (decided from the tax IDs). The server reads it, checks the amounts, judges deductibility and stores it in Documents; each read is billed to the company's credit. Give exactly one source. attachment\_id (a file sent in this chat) is read now and answers the record and `review` codes. direction\_unknown means ask whether they issued or received it and retry with direction; a name match alone also needs this confirmation. country\_unknown means ask the supplier/customer country and retry with counterparty\_country and the direction from the answer. url (an HTTPS download link, such as one a connected Drive returns) or file\_id (a file already in Documents) is read in the background: the call answers a job\_id at once; call document\_status later to see what each became. Several documents can be queued one call each. upload\_id (a file you uploaded with upload) is read in the background too.

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {
        "attachment_id": {
          "description": "The attachment_id of the photo or file the person sent in this chat.",
          "type": "string"
        },
        "counterparty_country": {
          "description": "Only when known: supplier country for an expense or customer country for income, as a two-letter country code. Use it to answer country_unknown; never assume ES.",
          "type": "string"
        },
        "direction": {
          "description": "Only when known: income when the company issued the document, expense when it received it.",
          "enum": [
            "income",
            "expense"
          ],
          "type": "string"
        },
        "file_id": {
          "description": "A file already in the company's Documents.",
          "type": "string"
        },
        "filename": {
          "description": "Name to store a downloaded document under.",
          "type": "string"
        },
        "upload_id": {
          "description": "The upload_id from upload, once the file was PUT to its upload_url.",
          "type": "string"
        },
        "url": {
          "description": "HTTPS link that downloads the PDF or image, for example from a connected Drive.",
          "type": "string"
        }
      },
      "type": "object"
    }
    ```
  </Accordion>

  <Accordion title="get">
    Read one expense belonging to this company, including its saved version, deductibility and review codes.

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {
        "id": {
          "description": "Company-scoped expense UUID.",
          "type": "string"
        }
      },
      "required": [
        "id"
      ],
      "type": "object"
    }
    ```
  </Accordion>

  <Accordion title="list">
    List the company's expenses, amounts, AEAT category (category\_proposed when Melso proposed it and nobody reviewed it), deductible classifications, Melso's deductibility estimate and saved versions.

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {},
      "type": "object"
    }
    ```
  </Accordion>

  <Accordion title="update">
    Edit only supplied fields at expected\_version. Rechecks amounts and client file access, and clears the review codes.

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {
        "attachment_id": {
          "description": "A photo or file the person sent in this chat, by its attachment_id. It is stored in their Documents as the expense's evidence; use it instead of file_id.",
          "type": "string"
        },
        "category": {
          "description": "The AEAT expense concept code of the libro registro de gastos (for example G22 Otros servicios exteriores, G17 telefonía e internet, G45 cuota de autónomo), or null for none. Never guess it: leave it out when unsure. Setting it marks a category Melso proposed as reviewed.",
          "enum": [
            "G01",
            "G02",
            "G03",
            "G04",
            "G05",
            "G45",
            "G46",
            "G07",
            "G08",
            "G09",
            "G10",
            "G11",
            "G12",
            "G13",
            "G14",
            "G15",
            "G16",
            "G17",
            "G18",
            "G19",
            "G40",
            "G41",
            "G42",
            "G20",
            "G22",
            "G44",
            "G23",
            "G24",
            "G25",
            "G26",
            "G27",
            "G28",
            "G29",
            "G30",
            "G31",
            "G32",
            "G33",
            "G38",
            "G34",
            "G35",
            "G36",
            "G43",
            "G37",
            "G39",
            "G47",
            null
          ],
          "type": [
            "string",
            "null"
          ]
        },
        "date": {
          "description": "Expense calendar date YYYY-MM-DD.",
          "type": "string"
        },
        "deductible": {
          "description": "Whether it is a deductible expense of the activity, defaults to unsure. Changing it clears the reason Melso gave.",
          "enum": [
            "yes",
            "no",
            "unsure"
          ],
          "type": "string"
        },
        "document_number": {
          "description": "Supplier's original document number.",
          "type": "string"
        },
        "expected_version": {
          "description": "Version from get/list. A stale version is refused.",
          "minimum": 1,
          "type": "integer"
        },
        "file_id": {
          "description": "Readable permanent client Library file UUID for evidence.",
          "type": "string"
        },
        "id": {
          "description": "Company-scoped expense UUID.",
          "type": "string"
        },
        "irpf_amount": {
          "description": "Nonnegative EUR IRPF withheld on the received invoice as a decimal string.",
          "type": "string"
        },
        "irpf_rate": {
          "description": "IRPF withheld on the received invoice as a 0 to 100 percentage string, empty when none.",
          "type": "string"
        },
        "subtotal": {
          "description": "Nonnegative EUR subtotal as a decimal string.",
          "type": "string"
        },
        "supplier_country": {
          "description": "Supplier country as a two-letter code, defaults to ES.",
          "type": "string"
        },
        "supplier_name": {
          "description": "Supplier name.",
          "type": "string"
        },
        "supplier_tax_id": {
          "description": "Supplier's tax ID.",
          "type": "string"
        },
        "total": {
          "description": "Nonnegative EUR total; must equal subtotal plus vat_amount.",
          "type": "string"
        },
        "vat_amount": {
          "description": "Nonnegative EUR VAT as a decimal string.",
          "type": "string"
        },
        "vat_rate": {
          "description": "Applied VAT rate as a 0 to 100 percentage string, empty when unknown. Refused with a non-taxable vat_treatment.",
          "type": "string"
        },
        "vat_treatment": {
          "description": "VAT treatment, defaults to taxable. Non-taxable treatments carry no VAT amount or rate.",
          "enum": [
            "taxable",
            "exempt",
            "reverse_charge",
            "not_subject"
          ],
          "type": "string"
        }
      },
      "required": [
        "id",
        "expected_version"
      ],
      "type": "object"
    }
    ```
  </Accordion>

  <Accordion title="upload">
    Get a link to upload a local PDF or photo (at most 15 MB) when you can run commands: PUT the file to upload\_url, then call from\_document with upload\_id. Without a shell, give the person web\_upload\_url to drop the files there instead.

    ```json theme={null}
    {
      "additionalProperties": false,
      "properties": {
        "content_type": {
          "description": "The file's type.",
          "enum": [
            "application/pdf",
            "image/jpeg",
            "image/png",
            "image/webp",
            "image/gif"
          ],
          "type": "string"
        },
        "filename": {
          "description": "The file's name, such as factura-0142.pdf.",
          "type": "string"
        },
        "size_bytes": {
          "description": "The file's exact size in bytes.",
          "maximum": 15728640,
          "minimum": 1,
          "type": "integer"
        }
      },
      "required": [
        "filename",
        "content_type",
        "size_bytes"
      ],
      "type": "object"
    }
    ```
  </Accordion>
</AccordionGroup>

## Output

The selected expense records, saved changes, document status, or an upload link/receipt according to the action. Extraction can remain pending; inspect document status before relying on its fields.

The result uses MCP `content` blocks; JSON payloads are encoded in text and may also appear in `structuredContent`. Check `isError` before reading a success payload. The server does not currently declare an `outputSchema`, so treat additional fields as extensible. [Result handling](/mcp/results).

## Example

Use an OAuth access token issued for this MCP resource (a Run token for Run-only tools). Replace example identifiers with values from your own account. Write actions change data.

```bash theme={null}
curl --fail-with-body https://melso.ai/api/mcp \
  -H "Authorization: Bearer $MELSO_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data-binary @- <<'JSON'
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "expenses",
    "arguments": {
      "action": "list"
    }
  }
}
JSON
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.