# Dubsado API and MCP server

> Dubsado has no public API (checked 11 Oct 2026). Its only official connection is Zapier, on the Premier plan: five triggers and one action, Create Project.

Client management for creative service businesses: projects, proposals, contracts, invoices, forms and scheduling in one place.

## What is the Dubsado API?

Cotlet's Dubsado API exposes 14 endpoints for your own Dubsado account: list projects, get project, list clients, list form templates, list forms, get form responses, list invoices, create project, update project status, apply form template, send form, create invoice, send invoice and record manual payment. The list_projects endpoint returns projects with client, lead or job, status, tags and project date. Each endpoint takes simple JSON inputs like project_id, status or limit and works both as an MCP tool for agents and as a REST call for scripts.

- **Category:** [Invoicing & freelance CRM](https://cotlet.dev/integrations/category/invoicing-freelance-crm)
- **Endpoints:** 14 (7 read, 7 write)
- **Updated:** 2026-10-11

Dubsado has no public API (checked 11 Oct 2026). Cotlet is a hosted MCP server and REST API for Dubsado with 14 endpoints (7 read, 7 write): your AI agent signs in as you and does the work.

## Does Dubsado have an official API?

Dubsado has no public API (checked 11 Oct 2026). Its only official connection is Zapier, on the Premier plan: five triggers and one action, Create Project.

| Task | Dubsado official | Cotlet |
|---|---|---|
| Create a project for a new client | Partly: Zapier "Create Project" action, Premier plan only | Yes |
| List projects and clients | Partly: Zapier triggers fire on new projects and status changes; no listing | Yes |
| Change a project status | No: Only Dubsado Flows, inside the app, can change a status | Yes |
| Send a proposal, contract or questionnaire | No | Yes |
| Read form responses and form status | Partly: Zapier "Contract Signed" trigger only | Yes |
| Create and send an invoice | No | Yes |
| List unpaid invoices | Partly: Zapier "New Payment Received" trigger only; no list | Yes |
| Log a payment received outside Dubsado | No | Yes |

Sources: [Dubsado Help: Dubsado triggers and actions in Zapier](http://help.dubsado.com/en/articles/15920601-dubsado-triggers-and-actions-in-zapier), [Dubsado Help: Connecting with Zapier (Premier plan required)](http://help.dubsado.com/en/articles/15920600-connecting-with-zapier), [Dubsado triggers and actions on Zapier](https://zapier.com/apps/dubsado/integrations), [Official AI Information: Dubsado (plans, Flows, integrations)](https://www.dubsado.com/llm-info), [Dubsado Help: Flow triggers, client progress (Premier Flows)](https://help.dubsado.com/en/articles/15668761-flow-triggers-client-progress)

## For AI agents

```text
Dubsado has no public API (checked 11 Oct 2026). Its only official connection is Zapier, on the Premier plan: five triggers and one action, Create Project.
Cotlet provides a hosted MCP server and REST API for Dubsado: 14 tools (7 read, 7 write).
Access       Request access at https://cotlet.dev/app/signup?app=dubsado; we email the API key.

MCP server   https://cotlet.dev/mcp/v1
REST base    https://cotlet.dev/api/v1/dubsado
Auth         Authorization: Bearer <COTLET_API_KEY>. Listing endpoints and schemas needs no key; calling an endpoint needs one.
Tools        list_projects, get_project, list_clients, list_form_templates, list_forms, get_form_responses, list_invoices, create_project, update_project_status, apply_form_template, send_form, create_invoice, send_invoice, record_manual_payment
Confirm      send_form, create_invoice, send_invoice, record_manual_payment (by default the user approves each call; the user can switch this off per tool, e.g. for scheduled automations)
Markdown     https://cotlet.dev/integrations/dubsado-api-mcp-server.md

How access works:
1. The user requests access at https://cotlet.dev/app/signup?app=dubsado (Dubsado is pre-selected). Each request is reviewed and the API key is sent by email.
2. The user signs in to Dubsado once in a browser. An agent cannot do this step.
3. The API key goes into the MCP client or the REST call as a bearer token.

Fits: people who want a hosted Dubsado server that someone else maintains, including non-developers.

Policy: Cotlet never stores passwords, never solves CAPTCHAs, never bypasses MFA.
Company: legal details in the Terms of service at https://cotlet.dev/terms. Contact contact@cotlet.dev.
Session: the user signs in to Dubsado in a browser; Cotlet keeps only the session, AES-256 encrypted, revocable in the dashboard at any time.
Terms: the user stays responsible for following Dubsado's terms; Cotlet is not affiliated with Dubsado.
```

## What can an AI agent do in Dubsado?

Cotlet is best for freelancers and small creative studios on Dubsado who want their AI agent to open projects, send proposals and invoices, read form answers and chase payments without running or fixing a server.

- **[Send a proposal to a new lead](https://cotlet.dev/integrations/dubsado-api-mcp-server/send-proposal-to-new-lead)**: "Maya Chen (maya@example.com) asked about a spring brand shoot in my Instagram DMs. Create a lead project "Spring brand shoot" and send her my Brand Photography proposal with a short personal note." → `list_clients`, `create_project`, `list_form_templates`, `apply_form_template`, `send_form`
- **[Summarize questionnaire answers before calls](https://cotlet.dev/integrations/dubsado-api-mcp-server/summarize-questionnaire-answers)** (runs: weekly): "Every Monday, summarize the questionnaire and lead capture answers my leads completed last week: what they want, the date, the budget, and anything that clashes with a booked job." → `list_projects`, `list_forms`, `get_form_responses`
- **[Chase unsigned contracts](https://cotlet.dev/integrations/dubsado-api-mcp-server/chase-unsigned-contracts)** (runs: weekly): "Which contracts did I send that the client has not signed yet? Draft a short nudge for each, list the ones waiting on my countersignature, and move every project whose contract is signed to my "Booked" job status." → `list_forms`, `get_project`, `update_project_status`
- **Create and send an invoice**: "Send the client in "Acme rebrand" an invoice for the Logo package, due in 14 days." → `list_projects`, `create_invoice`, `send_invoice`
- **[Log offline payments on invoices](https://cotlet.dev/integrations/dubsado-api-mcp-server/log-offline-payments)** (runs: weekly): "Here are this week's checks and e-transfers. Match each one to the open Dubsado invoice it pays, log it as a manual payment, and list who still owes me." → `list_clients`, `list_invoices`, `record_manual_payment`
- **Move signed projects to a job status** (runs: daily): "Move every project where the contract is signed to the "Booked" job status." → `list_forms`, `update_project_status`

## Can Dubsado automations run on a schedule in n8n, Make or Zapier?

Yes. Cotlet does not replace your automation platform: it gives it a Dubsado connection it does not have, with the same API key as your agent. Write actions ask for your OK by default; switch that off in your dashboard for the tools you choose, for example to summarize questionnaire answers before calls, and the schedule runs on its own. Cotlet runs in the cloud, so it keeps going while your computer is off.

| Where | How to connect | How to schedule |
|---|---|---|
| Your AI agent | Add https://cotlet.dev/mcp/v1 with your API key. | A scheduled agent run, for example a Claude Code routine. |
| n8n | MCP Client node with https://cotlet.dev/mcp/v1, or an HTTP Request node to https://cotlet.dev/api/v1/dubsado/{tool}. | Schedule Trigger node. |
| Make | HTTP module: POST https://cotlet.dev/api/v1/dubsado/{tool} with an Authorization: Bearer header and a JSON body. | Scenario schedule. |
| Zapier | Webhooks by Zapier: POST https://cotlet.dev/api/v1/dubsado/{tool} with the same header and body. | Schedule by Zapier trigger. |
| Your own script | POST https://cotlet.dev/api/v1/dubsado/{tool} with your API key. | cron or GitHub Actions. |

## Tools

**For AI agents:** Every endpoint and its schema is public. The 14 endpoints on this page, with parameters and example responses, can be listed without an account. Calling one returns 403 until the account has an API key with access to Dubsado.

### list_projects

Projects with client, lead or job, status, tags and project date. Access: read. REST: `POST /api/v1/dubsado/list_projects`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `category` | enum | no | lead, job or all. Default: all. |
| `status` | string | no | Your project status name, e.g. "Proposal Sent". |
| `created_since` | date | no | Only projects created on or after this date. |
| `limit` | integer | no | 1 to 100. Default: 25. |
| `cursor` | string | no | Next page cursor from the previous call. |

Lists projects newest first. Category is lead or job and follows the status: Dubsado statuses are either lead or job statuses. Filter by status name, category or creation date to see what came in since your last check. Pages hold up to 100 projects; pass next_cursor back as cursor for the next page.

Example response:

```json
{
  "projects": [
    {
      "project_id": "prj_3d81b07e",
      "title": "Spring brand shoot",
      "client": {
        "client_id": "cli_41a7e2",
        "name": "Maya Chen",
        "email": "maya@example.com"
      },
      "category": "lead",
      "status": "Proposal Sent",
      "tags": [
        "Brand"
      ],
      "project_date": "2027-04-18",
      "created_at": "2026-10-07T13:12:00Z"
    }
  ],
  "next_cursor": null
}
```

### get_project

One project: client, status, dates, tags, notes, forms and invoices. Access: read. REST: `POST /api/v1/dubsado/get_project`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `project_id` | string | yes | Project ID from list_projects. |

Returns one project with its client, status, tags and notes, the forms in it with their status, and its invoices with balances. Use it to read a whole project in one call before you act on it.

Example response:

```json
{
  "project_id": "prj_3d81b07e",
  "title": "Spring brand shoot",
  "client": {
    "client_id": "cli_41a7e2",
    "name": "Maya Chen",
    "email": "maya@example.com"
  },
  "category": "lead",
  "status": "Proposal Sent",
  "tags": [
    "Brand"
  ],
  "project_date": "2027-04-18",
  "notes": "Referred by a past client.",
  "forms": [
    {
      "form_id": "frm_6f2a91c4",
      "type": "proposal",
      "name": "Brand Photography proposal",
      "status": "sent"
    }
  ],
  "invoices": []
}
```

### list_clients

Clients with name, email, phone and their projects. Access: read. REST: `POST /api/v1/dubsado/list_clients`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `query` | string | no | Search by name or email. |
| `limit` | integer | no | 1 to 100. Default: 25. |
| `cursor` | string | no | Next page cursor from the previous call. |

Lists clients, the people and companies you work with. Search by name or email. Each client lists its project IDs, which you pass to get_project. Pages hold up to 100 clients.

Example response:

```json
{
  "clients": [
    {
      "client_id": "cli_41a7e2",
      "name": "Maya Chen",
      "email": "maya@example.com",
      "phone": "+1 555 0100",
      "projects": [
        "prj_3d81b07e"
      ]
    }
  ],
  "next_cursor": null
}
```

### list_form_templates

Your form templates by type, to pick one to apply to a project. Access: read. REST: `POST /api/v1/dubsado/list_form_templates`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `type` | enum | no | proposal, contract, questionnaire, sub_agreement, lead_capture or all. Default: all. |

Returns the templates you built in Dubsado: proposals, contracts, questionnaires, sub-agreements and lead capture forms. Pass template_id to apply_form_template. Templates are read only here.

Example response:

```json
{
  "templates": [
    {
      "template_id": "tpl_5c20aa",
      "name": "Brand Photography proposal",
      "type": "proposal"
    },
    {
      "template_id": "tpl_81d9f3",
      "name": "Photography contract",
      "type": "contract"
    },
    {
      "template_id": "tpl_2e7b60",
      "name": "Shoot questionnaire",
      "type": "questionnaire"
    }
  ]
}
```

### list_forms

Forms across projects, or in one project, with type and status. Access: read. REST: `POST /api/v1/dubsado/list_forms`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `project_id` | string | no | Only forms in this project. |
| `type` | enum | no | proposal, contract, questionnaire, sub_agreement, lead_capture or all. Default: all. |
| `status` | string[] | no | Any of sent, viewed, action_required, completed. Default: all statuses. |
| `limit` | integer | no | 1 to 100. Default: 25. |
| `cursor` | string | no | Next page cursor from the previous call. |

Lists forms sent from projects, the same forms as Forms, All forms in Dubsado. Status is sent, viewed, action_required or completed. Action required means a contract waits for your countersignature. Filter by type, status or project. Pass form_id to get_form_responses.

Example response:

```json
{
  "forms": [
    {
      "form_id": "frm_a4410c7e",
      "project_id": "prj_8e15c3a2",
      "project_title": "Acme rebrand",
      "type": "contract",
      "name": "Design services contract",
      "status": "viewed"
    }
  ],
  "next_cursor": null
}
```

### get_form_responses

Answers from a completed form or lead capture form, as question and answer pairs. Access: read. REST: `POST /api/v1/dubsado/get_form_responses`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `form_id` | string | yes | Form ID from list_forms or apply_form_template. |
| `include_empty` | boolean | no | Include unanswered fields. Default: false. |

Returns the answers a client gave, in the order of the form, the same as the Responses view on the form. Only completed forms have responses. Questionnaires can be edited after completion, so the answers can change.

Example response:

```json
{
  "form_id": "frm_9b42e6d1",
  "type": "questionnaire",
  "name": "Shoot questionnaire",
  "project_id": "prj_3d81b07e",
  "responses": [
    {
      "question": "What is the shoot for?",
      "answer": "New website and press kit."
    },
    {
      "question": "Preferred location",
      "answer": "Studio, downtown"
    }
  ]
}
```

### list_invoices

Invoices with project, total, amount paid, balance and due date. Access: read. REST: `POST /api/v1/dubsado/list_invoices`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | enum | no | unpaid, paid or all. Default: unpaid. |
| `project_id` | string | no | Only invoices in this project. |
| `due_before` | date | no | Only invoices with a payment due before this date. |
| `limit` | integer | no | 1 to 100. Default: 25. |
| `cursor` | string | no | Next page cursor from the previous call. |

Lists invoices, newest first. The due date comes from the invoice payment plan and is empty when the invoice has none. Balance is the total minus the payments logged, including those logged by hand. Pages hold up to 100 invoices.

Example response:

```json
{
  "invoices": [
    {
      "invoice_id": "inv_20417",
      "project_id": "prj_8e15c3a2",
      "project_title": "Acme rebrand",
      "number": "0042",
      "total": "1200.00",
      "paid": "400.00",
      "balance": "800.00",
      "due_date": "2026-10-11"
    }
  ],
  "next_cursor": null
}
```

### create_project

New project for a new or existing client. Nothing is sent to the client. Access: write. REST: `POST /api/v1/dubsado/create_project`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `title` | string | yes | Project title, e.g. "Brand Photography". |
| `client_email` | string | yes | Existing client, or a new one is created. |
| `client_name` | string | no | Name for a new client. |
| `status` | string | no | One of your project status names. |
| `project_date` | date | no | Project date. |
| `tags` | string[] | no | Project tags. |
| `notes` | string | no | Notes on the project. |

Creates a project from a title and a client email. If the email is not in Dubsado, a new client is created, with client_name if you give one. The status must be one of your project statuses and decides whether the project is a lead or a job. This call sends nothing to the client, so it asks no confirmation. You can archive or delete the project in Dubsado.

Example response:

```json
{
  "project_id": "prj_3d81b07e",
  "title": "Spring brand shoot",
  "client": {
    "client_id": "cli_41a7e2",
    "name": "Maya Chen",
    "email": "maya@example.com"
  },
  "category": "lead",
  "status": "Inquiry",
  "created_at": "2026-10-11T09:00:00Z"
}
```

### update_project_status

Move a project to another of your statuses. Access: write. REST: `POST /api/v1/dubsado/update_project_status`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `project_id` | string | yes | Project ID from list_projects. |
| `status` | string | yes | One of your project status names. |

Moves one project to a status you already have. A project can move from a lead status to a job status; Dubsado does not turn a status from one kind into the other. The call sends nothing to the client and you undo it with one more call, so it asks no confirmation. A Flow that starts on a status change still runs.

Example response:

```json
{
  "project_id": "prj_3d81b07e",
  "previous_status": "Proposal Sent",
  "status": "Booked",
  "category": "job"
}
```

### apply_form_template

Add a project copy of a proposal, contract, questionnaire or sub-agreement. Not sent yet. Access: write. REST: `POST /api/v1/dubsado/apply_form_template`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `project_id` | string | yes | Project ID from list_projects. |
| `template_id` | string | yes | Template ID from list_form_templates. |

Adds a copy of a template to one project and returns its form_id. Changes to the copy do not touch your template. Nothing is sent and the form is not added to the client portal, so this call asks no confirmation. Send it with send_form, or remove the copy in Dubsado.

Example response:

```json
{
  "form_id": "frm_6f2a91c4",
  "project_id": "prj_3d81b07e",
  "type": "proposal",
  "name": "Brand Photography proposal",
  "status": "not_sent"
}
```

### send_form

Email a proposal, contract, questionnaire or sub-agreement to the client. Access: write, asks the user first. REST: `POST /api/v1/dubsado/send_form`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `form_id` | string | yes | Form ID from list_forms or apply_form_template. |
| `subject` | string | no | Email subject. Default: from your email template. |
| `message` | string | no | Email body. Default: from your email template. |

Emails the form to the client with a link to it. Without subject and message it uses your default email template for the form. After the client completes it, the form is locked, except questionnaires. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "form_id": "frm_6f2a91c4",
  "project_id": "prj_3d81b07e",
  "type": "proposal",
  "status": "sent",
  "sent_to": "maya@example.com",
  "sent_at": "2026-10-11T09:02:00Z"
}
```

### create_invoice

Draft an invoice in a project from your packages or line items. Not emailed yet. Access: write, asks the user first. REST: `POST /api/v1/dubsado/create_invoice`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `project_id` | string | yes | Project ID from list_projects. |
| `package_ids` | string[] | no | IDs of your saved packages to add. |
| `line_items` | object[] | no | List of { name, quantity, price, description }. |
| `due_date` | date | no | Adds a payment plan with one payment due on this date. |

Creates an invoice in a project from saved packages, line items, or both. Dubsado numbers it automatically. The invoice date is the issue date; due_date adds a payment plan with one payment on that date. An invoice worth more than $0 appears in the client portal before it is emailed, so this call needs your OK. Email it with send_invoice. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "invoice_id": "inv_20417",
  "project_id": "prj_8e15c3a2",
  "number": "0042",
  "status": "not_sent",
  "line_items": [
    {
      "name": "Logo package",
      "quantity": 1,
      "price": "1200.00"
    }
  ],
  "total": "1200.00",
  "balance": "1200.00",
  "due_date": "2026-10-25"
}
```

### send_invoice

Email the invoice to the client with a link to it. Access: write, asks the user first. REST: `POST /api/v1/dubsado/send_invoice`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `invoice_id` | string | yes | Invoice ID from list_invoices or create_invoice. |
| `message` | string | no | Email body. Default: from your email template. |

Emails the invoice to the client with the invoice link. Without a message it uses your default email template. After it is sent, the automatic payment reminders of Dubsado follow the payment plan. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "invoice_id": "inv_20417",
  "status": "sent",
  "sent_to": "client@example.com",
  "sent_at": "2026-10-11T09:05:00Z"
}
```

### record_manual_payment

Log a payment received outside Dubsado against an invoice. Access: write, asks the user first. REST: `POST /api/v1/dubsado/record_manual_payment`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `invoice_id` | string | yes | Invoice ID from list_invoices or create_invoice. |
| `amount` | string | yes | Amount, e.g. "400.00". Not more than the remaining balance. |
| `paid_on` | date | yes | Date received. |
| `method` | enum | yes | cash, check, credit, e_transfer, paypal, stripe, square, authorize_net or other. |
| `description` | string | no | Optional note on the payment. |

Logs a payment you received outside Dubsado, such as cash or a check, on one invoice. The amount cannot be more than the remaining balance, and a payment for the full balance moves the invoice to Paid. It does not cancel autopay. Only manually logged payments can be edited or deleted, in Dubsado. By default you confirm each call; you can switch that off for this tool.

Example response:

```json
{
  "invoice_id": "inv_20417",
  "amount": "400.00",
  "method": "check",
  "paid_on": "2026-10-12",
  "balance": "800.00",
  "invoice_status": "unpaid"
}
```

## How do I connect Dubsado to Claude Code, Codex or Cursor?

Connecting Dubsado takes three steps: request access, sign in to Dubsado once, then add one MCP server or call the REST API with the same key.

### Connect Dubsado to your agent.

1. **Create an account** Sign up and add Dubsado in the console. Your API key is there too.

2. **Sign in to Dubsado once** Open the connect page from the console and sign in to Dubsado the way you always do. We keep the session, never your password, and you can revoke it anytime.

3. **Add Cotlet to your agent** Paste the snippet for your client. The same server and key serve every app you connect, so you do this once.

   Claude Code:

```
claude mcp add --transport http cotlet \
  https://cotlet.dev/mcp/v1 \
  --header "Authorization: Bearer $COTLET_API_KEY"
```

   Cursor:

```
{
  "mcpServers": {
    "cotlet": {
      "url": "https://cotlet.dev/mcp/v1",
      "headers": {
        "Authorization": "Bearer ${COTLET_API_KEY}"
      }
    }
  }
}
```

   Codex:

```
# ~/.codex/config.toml
[mcp_servers.cotlet]
url = "https://cotlet.dev/mcp/v1"
bearer_token_env_var = "COTLET_API_KEY"
```

4. **Ask your agent** Ask in plain words. Your agent finds the Dubsado tools on the server and calls them for you; anything that reaches other people waits for your OK unless you switch that off for a tool.

```
Maya Chen (maya@example.com) asked about a spring brand shoot in my Instagram DMs. Create a lead project "Spring brand shoot" and send her my Brand Photography proposal with a short personal note.
```

### Call Dubsado from your scripts.

1. **Export your API key** Your scripts use the same API key as your agent. Keep it in an environment variable, never in your code.

```
export COTLET_API_KEY="cotlet_..."
```

2. **Call a tool** Every tool is a POST endpoint at /api/v1/dubsado/{tool}. Send its parameters as JSON, exactly as listed in the endpoints above.

```
curl https://cotlet.dev/api/v1/dubsado/send_form \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"form_id":"frm_6f2a91c4","subject":"Your proposal for Spring brand shoot"}'
```

3. **Read the result** You get plain JSON back, ready for your script. A failed call costs nothing.

```
{
  "form_id": "frm_6f2a91c4",
  "project_id": "prj_3d81b07e",
  "type": "proposal",
  "status": "sent",
  "sent_to": "maya@example.com",
  "sent_at": "2026-10-11T09:02:00Z"
}
```

## Why use Cotlet for Dubsado?

**Built for agents**

- One MCP server for every app you connect.
- The same tools as a REST API for scripts and cron jobs.
- Works with Claude Code, Codex and Cursor.

**Your login stays yours**

- You sign in to Dubsado yourself. We keep only the session, encrypted with AES-256.
- The model never sees a login.
- No stored passwords, no CAPTCHA solving, no MFA bypass.

**You stay in control**

- Pick read only, or read and write.
- Anything that reaches other people waits for your OK, unless you switch it off per tool.
- Revoke access in one click.

**Kept working for you**

- We test every integration daily.
- When Dubsado changes, the tool pauses until we fix it.
- Failed calls cost nothing.

## Is there a Dubsado MCP server on GitHub?

Zapier is the only official way in, and it is narrow: it reacts to five events and can create a project, but cannot send anything or read your data. Zapier also offers an MCP server for Dubsado, and it exposes the same five triggers and one action.

|  | Zapier | Cotlet |
|---|---|---|
| Setup | Generate an API key under Settings, Connections (Admin or Owner) and paste it into Zapier | Request access, sign in to Dubsado once in your browser, add one MCP server or API key |
| What it can do | 5 triggers and 1 action: Create Project | Projects, clients, forms, proposals, contracts, invoices and manual payments |
| Sending to clients | Not possible; you send from Dubsado by hand | Forms and invoices, each send confirmed by you by default |
| Dubsado plan | Premier plan required (trial accounts include it) | Works with the plan you have; features your plan lacks stay unavailable |
| When Dubsado changes | Zapier maintains its Dubsado app | Our team tests it daily and fixes it for you; failed calls are free |
| Your Dubsado session | An API key you generated, shown once, which you treat like a password | Session only, encrypted in an EU vault; we never store your password |
| Price | Zapier plan on top of Dubsado Premier | Free 7-day trial with 5,000 credits, then credits per call |

### Which one fits you

**Pick Cotlet if**

- you are not a developer, or you do not want to maintain a server
- you need it to keep working when Dubsado changes, without checking it yourself
- your agent or a script should run it on a schedule, also while your computer is off

**Pick an open-source server if**

- you are comfortable installing, updating and fixing it yourself
- you want the session to stay on your own computer
- you only need it now and then, from one MCP client

## How much does the Dubsado API cost?

Free 7-day trial with 5,000 credits, no card needed. After that, the Dubsado API comes with the Cotlet plan, from $29 a month for 3,000 credits, with no limit on apps. Each month's credits stay valid for 3 months, so unused credits add up.

| Size | Price | Credits / month | Per credit |
|---|---|---|---|
| Solo | $29/mo | 3,000 | about $0.0097 |
| Pro | $99/mo | 12,000 | about $0.0083 |
| Agency | $299/mo | 40,000 | $0.0075 |

Each successful call uses credits for the work it takes; failed calls and timeouts cost nothing. A hard spend cap is on by default. Authenticate with the `Authorization: Bearer` header. [See full pricing](https://cotlet.dev/pricing)

## How Cotlet holds your access

Cotlet hosts MCP servers and REST APIs for apps with no usable API. Your agent works in your own Dubsado account.

- **Company details:** The legal name, address and registration numbers of the company behind Cotlet are in the Terms of service. [Terms](https://cotlet.dev/terms)
- **Your session:** You sign in to Dubsado yourself, in your browser. We keep only the session, never your password: encrypted with AES-256 in an EU vault, isolated to your account and used only when your agent calls a Dubsado tool you allowed. When it expires, your agent gives you a link to sign in again. [Security](https://cotlet.dev/security)
- **Revoking access:** Disconnect Dubsado in your dashboard: the session is deleted and access ends at once. Actions that reach other people wait for your OK unless you switch that off per tool.
- **What we never do:** Store passwords, solve CAPTCHAs or bypass MFA.
- **Dubsado's terms:** You use your own Dubsado account and stay responsible for following Dubsado's terms. Cotlet is independent and not affiliated with Dubsado. [Terms](https://cotlet.dev/terms)
- **Contact:** Questions about the company, security or an app: [contact@cotlet.dev](mailto:contact@cotlet.dev)

## Frequently asked questions

**How do I get access?**

Request access and pick Dubsado. Cotlet reviews each request and emails you your API key.

**Do I need to be technical?**

No. You sign in to Dubsado once in your browser and paste one command into your agent, or one URL into n8n. Your agent can walk you through it. There is no server to install, update or fix.

**Is a hosted server safe? My Dubsado session would leave my computer.**

Cotlet keeps your Dubsado session encrypted with AES-256 in an EU vault, isolated to your account and used only for the tools you allow: read only, or read and write. The AI model never sees it, and you revoke it in one click. A local server keeps the same session in a file on your computer, readable by any program you run, and needs a fresh sign-in whenever it expires.

**Do I need the Premier plan or Zapier?**

No. Cotlet works in your own Dubsado account and does not use the Zapier connection, which Dubsado limits to the Premier plan (checked 11 Oct 2026). Features your plan lacks stay unavailable: public proposal links, for example, need Premier.

**Can my agent send a contract for signature?**

Yes. A contract is a form type: apply_form_template adds your contract to the project and send_form emails it, which you confirm by default. When the client signs, Dubsado locks the contract and emails the client a copy.

**Will my agent overlap with my Dubsado Flows?**

No. Flows keep running as you set them up. Your agent adds work on top of them, for example summarizing answers or drafting reminders, and Flows that start on a status change still run when it moves a project.

**Can my agent post or send messages in Dubsado without asking me?**

No. Every call to send_form, create_invoice, send_invoice or record_manual_payment waits for your OK by default. For scheduled automations you can switch confirmation off per tool in your dashboard, for example only for approvals. create_project, update_project_status, apply_form_template runs without asking, because it sends nothing to anyone and one call undoes it.

**Can I use the Dubsado API in n8n?**

Yes. Add https://cotlet.dev/mcp/v1 with your API key in n8n's MCP Client node, or call https://cotlet.dev/api/v1/dubsado/{tool} from the HTTP Request node.
