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

  1. Create an API key in Settings, API Keys. Copy it; you will only see it once.
  2. Add the key to your environment as COASTLINE_API_KEY.
  3. Register the server with your AI tool (see the panel).
  4. 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

ToolKindWhat it does
list_expensesReadFind expenses. Filter by project, date range, receipt presence, and whether your integration has already handled them.
get_expenseReadOne expense in full, including a signed receipt link and the linked project with its custom fields resolved.
read_receiptReadThe receipt image itself, so the assistant can read the pre-tax subtotal, tax line, store location, and purchase time.
find_projectReadTurn a project number, name, or customer name into a project id.
get_projectReadOne project with its custom fields, including field types and labels.
set_expense_external_referenceWriteRecord that an outside system handled an expense and what identifier it assigned.
list_price_listsReadFind price lists by name.
save_price_listWriteCreate or update a price list. Creating with a duplicate name returns the existing list's id instead of a second list.
list_catalog_itemsReadFind catalog items. Filter by price list, item type, category, SKU, or a name/SKU search.
get_catalog_itemReadOne catalog item in full.
save_catalog_itemWriteCreate or update a catalog item. Creating with a duplicate SKU returns the existing item's id instead of a second item.
set_catalog_item_imageWriteSet or remove a catalog item's photo, from a URL or a local file.
delete_catalog_itemWriteDelete a catalog item. Destructive; cannot be undone.
add_project_photosWriteAdd 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:

  1. list_expenses with your own namespace and reconciliation: unreconciled. That is the work queue.
  2. get_expense for one of them. The project's custom fields come back with it, which is how you learn which outside record it belongs to.
  3. read_receipt only when you need the subtotal, tax line, or store details off the paper.
  4. Create the counterpart in the other system.
  5. set_expense_external_reference straight 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.