Getting started
Connect your AI assistant
Coastline ships an MCP server, which lets an AI assistant read your workspace directly instead of clicking through the web app. It works with any tool that speaks the Model Context Protocol: Claude Code, Claude Desktop, Cursor, Codex, and others.
It runs on your own machine. Nothing is hosted, no data passes through a third party, and your API key never leaves your computer.
What it is good for
The job most people want: every company-card purchase has to exist both in Coastline and in whatever system does the ordering or the accounting. Done by hand it is a few minutes per receipt, and the risk is doing one twice.
With the server connected, an assistant can list the expenses nothing has handled yet, read one including its receipt image, find which outside record the project corresponds to, and then mark the expense handled so it never comes back around. That last step is what makes it safe to leave running.
The same server also manages the product catalog: price lists and the items on them, including their photos. An assistant can find, create, and update items and price lists, and set or remove an item's image from a URL or a local file.
It can also add photos to a project from files on your computer: point it at a folder and every photo and video in it lands on the project's Photos tab, dated from when it was taken, with anything already there skipped.
Setup
- Create an API key in Settings, API Keys. Copy it; you will only see it once.
- Add the key to your environment as
COASTLINE_API_KEY. - Register the server with your AI tool (see the panel).
- Restart the tool. Ask it to list your unreconciled expenses.
Only workspace admins can create API keys, and expenses require the Professional plan. A key acts as the member who created it, so it can reach exactly what that person can reach in the app and nothing more. Revoke it any time from the same settings page; the assistant loses access immediately.
Tools
| Tool | Kind | What it does |
|---|---|---|
| list_expenses | Read | Find expenses. Filter by project, date range, receipt presence, and whether your integration has already handled them. |
| get_expense | Read | One expense in full, including a signed receipt link and the linked project with its custom fields resolved. |
| read_receipt | Read | The receipt image itself, so the assistant can read the pre-tax subtotal, tax line, store location, and purchase time. |
| find_project | Read | Turn a project number, name, or customer name into a project id. |
| get_project | Read | One project with its custom fields, including field types and labels. |
| set_expense_external_reference | Write | Record that an outside system handled an expense and what identifier it assigned. |
| list_price_lists | Read | Find price lists by name. |
| save_price_list | Write | Create or update a price list. Creating with a duplicate name returns the existing list's id instead of a second list. |
| list_catalog_items | Read | Find catalog items. Filter by price list, item type, category, SKU, or a name/SKU search. |
| get_catalog_item | Read | One catalog item in full. |
| save_catalog_item | Write | Create or update a catalog item. Creating with a duplicate SKU returns the existing item's id instead of a second item. |
| set_catalog_item_image | Write | Set or remove a catalog item's photo, from a URL or a local file. |
| delete_catalog_item | Write | Delete a catalog item. Destructive; cannot be undone. |
| add_project_photos | Write | Add photos and videos from local files or a folder to a project. Built for hundreds at once; files already on the project are skipped. |
Expense amounts include sales tax
amount_tax_inclusive is the total actually paid, tax already in it. If you are pushing into a system that adds its own sales tax, set that tax to zero. Otherwise every record is inflated by the tax rate, and the error reaches accounting without anybody noticing. The tools say this too, so an assistant reading them gets the warning before it writes anything.
The reconciliation loop
The pattern most integrations follow, and the one worth copying:
list_expenseswith your own namespace andreconciliation: unreconciled. That is the work queue.get_expensefor one of them. The project's custom fields come back with it, which is how you learn which outside record it belongs to.read_receiptonly when you need the subtotal, tax line, or store details off the paper.- Create the counterpart in the other system.
set_expense_external_referencestraight away, with the identifier that system assigned.
Step 5 is the one that matters. Assistants retry, webhooks deliver more than once, and scheduled runs overlap. The stamp is the only durable record that an expense has already been dealt with, and without it a second run creates a second purchase order. Use the same namespace in step 1 and step 5, or the expense never leaves the queue. Setting the same reference twice is harmless.
Limits
- About 100 requests per minute. Ask for larger pages rather than more calls.
- Lists return at most 100 rows; follow the returned cursor for the rest.
- Receipt links are signed, valid 24 hours, and need no login. Treat one like a password.
- Photos up to 50 MB and videos up to 500 MB. A photo upload costs about two requests per 100 files, so large folders stay well inside the limit.
- Everything is scoped to the workspace the key belongs to. There is no argument that reaches another workspace.
The server calls the same endpoints documented here, so anything it can do you can also do directly. See expenses, catalog, photos, custom fields, and webhooks to have Coastline notify you the moment a receipt is captured in the field.
Adding a folder of photos to a project
Ask for it by project: “add every photo in ~/Jobs/Smith to project #1042”. The assistant finds the project with find_project and calls add_project_photos with the folder. Each file is hashed first, so one already on the project is reported as a duplicate instead of uploaded twice, and running the same request again after an interruption sends only what is missing.
Copying a catalog between two workspaces
A key is scoped to one workspace, so moving catalog items and price lists from one workspace to another means registering the server twice, once per workspace, each with its own key (see the panel). Never pass an item's image_url from one workspace straight into another; ask the assistant to download the bytes and set the image on the target item instead, since the source workspace owns that file.