Billy MCP by usefulapi
Read Billy invoices, bills, contacts, products and postings; create contacts and draft invoices.
¿Debería usar esto?
Calidad y seguridad
Basado en el análisis automatizado de las definiciones de herramientas y el cumplimiento del protocolo.
Costo de contexto
Este es el número aproximado de tokens que se consumen cada vez que las herramientas del servidor se cargan en el contexto de un modelo. Los recuentos más altos reducen la atención disponible para otras tareas.
Instalar
Instalación con un clic
Agrega esto a tu archivo `claude_desktop_config.json`:
{
"mcpServers": {
"billy": {
"url": "https://billy.usefulapi.io/mcp"
}
}
}Puntos de conexión remotos
https://billy.usefulapi.io/mcpstreamable-httpQué puede hacer
Inventario de herramientas
Herramientas (15)
🟢billy_get_organization
The Billy company the access token belongs to: id, name, address, registration (CVR) number, base currency, VAT settings, fiscal year, default payment terms, invoice numbering, default accounts. Good first call. GET /organization.
Esquema de entrada
{
"type": "object",
"properties": {},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_contacts(search, page, page_size)
List customers and suppliers: name, type, address, CVR/registration number, EAN, payment terms, customer/supplier flags. The API has no documented search filter, so `search` is applied to the returned page only (case-insensitive on name, contact number and registration number); page on with next_page to look further. Paged. GET /contacts.
Esquema de entrada
{
"type": "object",
"properties": {
"search": {
"description": "Keep only contacts on the returned page whose name, contactNo or registrationNo contains this text.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_get_contact(id)
One contact by id, with its contact persons (names and e-mail addresses). GET /contacts/{id}.
Esquema de entrada
{
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "The contact id (from billy_list_contacts)."
}
},
"required": [
"id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_invoices(state, contact_id, invoice_no, is_paid, min_entry_date, ...)
List sales invoices and credit notes (newest first by default): number, date, due date, state (draft/approved/voided), amount, tax, balance, isPaid, contactId, currency. Filter by state, customer, number, date, period, paid status or free text. Paged. GET /invoices.
Esquema de entrada
{
"type": "object",
"properties": {
"state": {
"description": "Only invoices in this state.",
"type": "string",
"enum": [
"draft",
"approved",
"voided"
]
},
"contact_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "Only invoices of this contact (from billy_list_contacts)."
},
"invoice_no": {
"description": "Exact invoice number.",
"type": "string",
"minLength": 1,
"maxLength": 50
},
"is_paid": {
"description": "true = only paid invoices, false = only unpaid.",
"type": "boolean"
},
"min_entry_date": {
"description": "Invoice date on or after (yyyy-mm-dd).",
"type": "string"
},
"max_entry_date": {
"description": "Invoice date on or before (yyyy-mm-dd).",
"type": "string"
},
"min_due_date": {
"description": "Due date on or after (yyyy-mm-dd).",
"type": "string"
},
"max_due_date": {
"description": "Due date on or before (yyyy-mm-dd); with is_paid=false this finds overdue invoices.",
"type": "string"
},
"entry_date_period": {
"type": "string",
"pattern": "^[A-Za-z0-9:.,-]{1,80}$",
"description": "Date period: all, year:2026, month:2026-03, quarter:2026-2, dates:2026-01-01...2026-01-31 ..."
},
"q": {
"description": "Free-text search over invoice number, order number, contact name, line description, amount.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"sort_property": {
"description": "Sort by (default entryDate).",
"type": "string",
"enum": [
"entryDate",
"dueDate",
"createdTime",
"invoiceNo",
"amount",
"balance",
"contact.name",
"approvedTime"
]
},
"sort_direction": {
"description": "Sort direction (default ASC).",
"type": "string",
"enum": [
"ASC",
"DESC"
]
},
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_get_invoice(id)
One invoice by id with its lines (product, description, quantity, unit price, amount, tax) and its payment associations. GET /invoices/{id}.
Esquema de entrada
{
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "The invoice id (from billy_list_invoices)."
}
},
"required": [
"id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_bills(state, contact_id, is_paid, min_entry_date, max_entry_date, ...)
List bills (purchase invoices from suppliers): supplier, dates, state (draft/approved/voided), amount, balance, isPaid, supplier invoice number. Filter by state, supplier, dates or paid status. Paged. GET /bills.
Esquema de entrada
{
"type": "object",
"properties": {
"state": {
"description": "Only bills in this state.",
"type": "string",
"enum": [
"draft",
"approved",
"voided"
]
},
"contact_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "Only bills of this supplier contact."
},
"is_paid": {
"description": "true = only paid bills, false = only unpaid.",
"type": "boolean"
},
"min_entry_date": {
"description": "Bill date on or after (yyyy-mm-dd).",
"type": "string"
},
"max_entry_date": {
"description": "Bill date on or before (yyyy-mm-dd).",
"type": "string"
},
"min_due_date": {
"description": "Due date on or after (yyyy-mm-dd).",
"type": "string"
},
"max_due_date": {
"description": "Due date on or before (yyyy-mm-dd).",
"type": "string"
},
"suppliers_invoice_no": {
"description": "Exact supplier invoice number.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"q": {
"description": "Free-text search over supplier name, description, voucher number, amount, supplier invoice number.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"sort_property": {
"description": "Sort by (default entryDate).",
"type": "string",
"enum": [
"entryDate",
"dueDate",
"createdTime",
"amount",
"balance",
"contact.name",
"voucherNo",
"suppliersInvoiceNo"
]
},
"sort_direction": {
"description": "Sort direction (default ASC).",
"type": "string",
"enum": [
"ASC",
"DESC"
]
},
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_get_bill(id)
One supplier bill by id with its lines. GET /bills/{id}.
Esquema de entrada
{
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "The bill id (from billy_list_bills)."
}
},
"required": [
"id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_products(search, page, page_size)
List products and services usable as invoice lines: name, product number, description, sales account, archived flag. The API has no documented search filter, so `search` is applied to the returned page only (name, productNo). Paged. GET /products.
Esquema de entrada
{
"type": "object",
"properties": {
"search": {
"description": "Keep only products on the returned page whose name or productNo contains this text.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_get_product(id)
One product by id with its unit prices per currency. GET /products/{id}.
Esquema de entrada
{
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "The product id (from billy_list_products)."
}
},
"required": [
"id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_accounts(is_bank_account, page, page_size)
The chart of accounts: account number, name, group, nature, VAT rate, bank-account flag and bank details (IBAN, bank name) of bank accounts. With is_bank_account=true this lists the bank accounts whose ids billy_list_bank_lines needs. Paged. GET /accounts.
Esquema de entrada
{
"type": "object",
"properties": {
"is_bank_account": {
"description": "true = only bank accounts.",
"type": "boolean"
},
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_tax_rates(page, page_size)
The company's VAT rates: name, rate (as a fraction, 0.25 = 25 percent), whether it applies to sales or purchases, active flag. Paged. GET /taxRates.
Esquema de entrada
{
"type": "object",
"properties": {
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_bank_lines(account_id, is_reconciled, status, side, min_entry_date, ...)
List the bank-statement lines of ONE bank account (read only; nothing is matched or reconciled): date, description, amount, side (debit/credit), reconciled flag, receipt state. Get the account id from billy_list_accounts with is_bank_account=true. Paged. GET /bankLines.
Esquema de entrada
{
"type": "object",
"properties": {
"account_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "The bank account id (required)."
},
"is_reconciled": {
"description": "true = only reconciled lines, false = only unreconciled.",
"type": "boolean"
},
"status": {
"description": "Line status (the API defaults to booked).",
"type": "string",
"enum": [
"pending",
"booked"
]
},
"side": {
"description": "Only debit (money in) or credit (money out) lines.",
"type": "string",
"enum": [
"debit",
"credit"
]
},
"min_entry_date": {
"description": "Entry date on or after (yyyy-mm-dd).",
"type": "string"
},
"max_entry_date": {
"description": "Entry date on or before (yyyy-mm-dd).",
"type": "string"
},
"entry_date_period": {
"type": "string",
"pattern": "^[A-Za-z0-9:.,-]{1,80}$",
"description": "Date period: all, year:2026, month:2026-03, quarter:2026-2, dates:2026-01-01...2026-01-31 ..."
},
"min_amount": {
"description": "Amount at least.",
"type": "number",
"minimum": 0,
"maximum": 1000000000000
},
"max_amount": {
"description": "Amount at most.",
"type": "number",
"minimum": 0,
"maximum": 1000000000000
},
"receipt_state": {
"description": "Only lines with a missing or uploaded receipt.",
"type": "string",
"enum": [
"missing_receipt",
"receipt_uploaded"
]
},
"q": {
"description": "Free-text search over description or amount.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"sort_property": {
"description": "Sort by (default entryDate).",
"type": "string",
"enum": [
"entryDate",
"amount"
]
},
"sort_direction": {
"description": "Sort direction (default ASC).",
"type": "string",
"enum": [
"ASC",
"DESC"
]
},
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"required": [
"account_id"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🟢billy_list_postings(account_id, min_entry_date, max_entry_date, entry_date_period, is_voided, ...)
List ledger postings (the bookkeeping entries): date, text, account, amount, side (debit/credit), currency, voided flag. Filter by account, date or period. Read only. Paged. GET /postings.
Esquema de entrada
{
"type": "object",
"properties": {
"account_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "Only postings on this account (from billy_list_accounts)."
},
"min_entry_date": {
"description": "Entry date on or after (yyyy-mm-dd).",
"type": "string"
},
"max_entry_date": {
"description": "Entry date on or before (yyyy-mm-dd).",
"type": "string"
},
"entry_date_period": {
"type": "string",
"pattern": "^[A-Za-z0-9:.,-]{1,80}$",
"description": "Date period: all, year:2026, month:2026-03, quarter:2026-2, dates:2026-01-01...2026-01-31 ..."
},
"is_voided": {
"description": "true = only voided postings, false = only live ones.",
"type": "boolean"
},
"q": {
"description": "Free-text search over the posting text and the originator name.",
"type": "string",
"minLength": 1,
"maxLength": 100
},
"page": {
"description": "Page number, 1-based (default 1). Use next_page from the previous reply.",
"type": "integer",
"minimum": 1,
"maximum": 100000
},
"page_size": {
"description": "Records per page, 1-200 (default 50).",
"type": "integer",
"minimum": 1,
"maximum": 200
}
},
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴billy_create_contact(name, type, country_id, street, zipcode, ...)
WRITE: create ONE new contact (customer and/or supplier) in the company's Billy account. It does not check for duplicates (call billy_list_contacts first) and nothing is sent to the contact. Not idempotent: a repeat call creates a second contact. POST /contacts.
Esquema de entrada
{
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Company or person name."
},
"type": {
"description": "company (default) or person.",
"type": "string",
"enum": [
"company",
"person"
]
},
"country_id": {
"description": "ISO country code (default DK).",
"type": "string",
"pattern": "^[A-Z]{2}$"
},
"street": {
"description": "Street and number.",
"type": "string",
"maxLength": 255
},
"zipcode": {
"description": "Postal code.",
"type": "string",
"maxLength": 20
},
"city": {
"description": "City.",
"type": "string",
"maxLength": 255
},
"phone": {
"description": "Phone number.",
"type": "string",
"maxLength": 50
},
"registration_no": {
"description": "CVR number (Denmark) or EU VAT number.",
"type": "string",
"maxLength": 50
},
"ean": {
"description": "EAN location number for e-invoicing (Denmark).",
"type": "string",
"maxLength": 20
},
"contact_no": {
"description": "Your own customer or supplier number.",
"type": "string",
"maxLength": 50
},
"email": {
"description": "Primary contact e-mail (stored as the primary contact person; nothing is sent).",
"type": "string",
"maxLength": 255,
"format": "email",
"pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
},
"is_customer": {
"description": "Customer flag (default true).",
"type": "boolean"
},
"is_supplier": {
"description": "Supplier flag (default false).",
"type": "boolean"
}
},
"required": [
"name"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}🔴billy_create_draft_invoice(contact_id, entry_date, currency_id, tax_mode, contact_message, ...)
WRITE: create ONE invoice in the DRAFT state for an existing contact. The invoice is NOT approved, booked, numbered into the ledger or sent: the user reviews it in Billy and approves and sends it there. The invoice number is assigned by Billy. No payment is created. Not idempotent: a repeat call creates a second draft. POST /invoices with state=draft.
Esquema de entrada
{
"type": "object",
"properties": {
"contact_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "The customer's contact id (from billy_list_contacts or billy_create_contact)."
},
"entry_date": {
"description": "Invoice date yyyy-mm-dd (default today, UTC).",
"type": "string"
},
"currency_id": {
"description": "Invoice currency, e.g. DKK (default: the company's base currency).",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"tax_mode": {
"description": "Whether unit prices include (incl) or exclude (excl) VAT (default: the company's setting).",
"type": "string",
"enum": [
"incl",
"excl"
]
},
"contact_message": {
"description": "Message to the customer shown at the top of the invoice PDF.",
"type": "string",
"maxLength": 2000
},
"lines": {
"minItems": 1,
"maxItems": 100,
"type": "array",
"items": {
"type": "object",
"properties": {
"product_id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,64}$",
"description": "The product id (from billy_list_products)."
},
"unit_price": {
"type": "number",
"minimum": -1000000000,
"maximum": 1000000000,
"description": "Price per unit in the invoice currency (VAT excluded unless tax_mode is incl)."
},
"quantity": {
"description": "Quantity (default 1).",
"type": "number",
"exclusiveMinimum": 0,
"maximum": 1000000000
},
"description": {
"description": "Text shown under the product name on the invoice.",
"type": "string",
"maxLength": 2000
}
},
"required": [
"product_id",
"unit_price"
]
},
"description": "1-100 invoice lines."
}
},
"required": [
"contact_id",
"lines"
],
"$schema": "https://json-schema.org/draft/2020-12/schema"
}Comunidad
Evidencia