Skip to main content

About

Programmatic access to your deal flow: fetch and search deals, spot deals going cold, and create, update, move, or archive deals from your own code. Edit pipeline custom-field definitions and open or move Scraper Health cards with reasoning recorded alongside each move. Pipeline structure (creating pipelines, editing stages) and pipeline analytics have their own page — see the Pipelines API. All operations go through the developer API gateway — one endpoint, called by operationId. If you haven’t set up a key yet, start with the Developer API Overview.

Operations

Reading deals (READ scope)

findDeals, surveyDeals and listStalledDeals are paginatedfindDeals and listStalledDeals return up to 50 rows per call; surveyDeals returns up to 45 (default 16). All take an offset and return totalCount + hasMore, so you can page through the full set. Advance offset by the number of rows returned until hasMore is false. For example, with limit: 16, request offsets 0, 16, and 32. Do not jump by 50 while using a smaller page size. See Result limits & truncation.
Both findDeals and surveyDeals return taskSummary.openTaskCount and taskSummary.openAppointmentCount. These count open items linked to the deal, not every task on its contacts. An openTaskCount of zero identifies a deal with no open task without reading its whole activity feed.

Saved deal filters (READ scope)

A saved deal filter does not fix its pipeline: supply the pipeline on every execution. Inline filterTree is not accepted by filterDeals; save the criteria first. Discover DEAL fields with listFilterFieldNames and listFilterFields, and manage filter folders through the Properties API. Check the owner’s userId before editing or deleting a shared filter.
Which deal read to reach forThree reads, three shapes of question. getDeal is one deal in full. findDeals is a handful of deals with everything on them — money, contacts, dates. surveyDeals gives a little on each row for grouping or “who owns what” sweeps. Page through all matches before describing the whole board, and take counts from totalCount, never from the length of one page.
Custom fields in search resultsfindDeals.customFieldValues and surveyDeals.customFieldValues include each recorded value and its field’s name (dealCustomField.name), without definition ids or types. An absent entry means the deal has no recorded value for that field; an empty list does not mean the pipeline has no custom fields. Use listDealCustomFields for definitions and ids before writing. Custom fields increase the response size; use a smaller limit when you need smaller pages.

Writing deals (WRITE scope)

Deal money fieldsCommission and team split each accept one source: a fixed *AmountCents or a *PercentBps, never both. commissionCents is the server-derived GCI to report. Participant splits allocate what remains after the team fee. For deal custom fields, use the value member that matches the definition type; DOLLAR values are plain numbers, not cents, and dropdown values are option labels.
Dropdown options replace the whole listOn updateDealCustomField, send every option you want to keep. Preserve each existing option’s { id, label }; add a new option with { label } and no id. Renaming with the existing id carries deal values, the default, saved filters, and queued bulk tasks to the new label. Omitting an option removes it; removal is refused while deals or filters reference it unless you supply optionDependencyResolutions. A default no longer present in the options is cleared. Field names must be unique within the pipeline.

Scraper Health cards

Benchmark keys are scoped to your organization. A key contains 1–200 lowercase letters, digits, or : _ . -, starting with a letter or digit. Concurrent upserts for the same key create one card. An upsert that finds an existing card does not change it or append an event; use the move operation for subsequent verdicts. Both writes take an event with healthActor: MONITOR | DOCTOR | PERSON and required why (1–4,000 characters). Optional checked, found, and nextTime are limited to 4,000 characters each; handoffSummary is limited to 600. Optional evidence fields are delivered, expected (fractional values allowed), and windowDays. Malformed events are rejected before writing. The server fills in the key owner and stage names. Read the reasoning with listDealActivity, narrowed to eventTypes: ["SCRAPER_HEALTH_MOVED"]. Its SuperJSON payload at json includes healthActor (stored as monitor, doctor, or person), fromStage, toStage, and the event’s reasoning and evidence. fromStage is null on the creation event. Moving to the current stage records a verdict without changing the stage; a different pipeline’s stage or a non-card deal is refused. Creation and stage changes also trigger ordinary stage-entry workflows.
Guard every card move and retryPass expectedUpdatedAt from getScraperHealthCard or your previous write. Omitting it only protects the server’s short read-to-write interval, so it can overwrite a move made after your earlier read. After a failed or timed-out call, re-read the card and its history before deciding to retry: the first move may have committed, and a repeated move can append the reasoning again. Use an Idempotency-Key on card writes to deduplicate request retries.
updateDeal replaces linked setsOn updateDeal, the contactIds, propertyIds, and userIds arrays replace the deal’s linked set — they do not append. To add one contact, send the full existing list plus the new id.
Guarding against a concurrent editPass expectedUpdatedAt — the updatedAt you got from getDeal, findDeals, or a previous write — to make the update conditional. The write applies only if the deal hasn’t changed since; otherwise nothing is written and you get CONFLICT. Use it whenever you decided what to write from a copy you read earlier, so a concurrent edit fails loudly instead of being silently overwritten.A guarded update is all-or-nothing: userIds, participantSplits, and customFieldValues are part of the same transaction as the core deal fields. A rejected value rolls back the whole edit, including title and stage changes. A successful write advances updatedAt, so re-read before using another concurrency guard.Without expectedUpdatedAt, the core write commits before the custom fields: a later custom-field failure can leave the title or stage changed. A deleted deal returns NOT_FOUND; an unparseable token returns BAD_USER_INPUT.
Deal file URLs are short-livedfileUrl from listDealFiles or attachDealFile is a time-limited signed HTTPS URL. Fetch it promptly, and don’t persist or share it — re-read listDealFiles rather than caching the URL. attachDealFile accepts an existing artifact id; it is not a raw-byte upload endpoint.
Organization guardDeal operations are org-guarded: the deal (and any destination stage) must belong to a pipeline owned by or shared with your organization, or the call returns 403 forbidden. Pipelines shared with your org through a partnership work normally. See Authorization for the full owned-vs-shared model.

Pipeline operations

The Pipelines API covers the rest of the deals domain:
  • Read structure with listPipelineNames, listPipelines, and listPipelineStages (READ).
  • Create and edit it with createPipeline, updatePipeline, addPipelineStages, updatePipelineStage, and reorderPipelineStages (WRITE).
  • Preview dependencies with getDeletionImpact (READ) before deletePipeline or deletePipelineStage (WRITE). Review the replacement options carefully: one permanently deletes the stage’s deals.
  • Read reporting with getPipelineAnalytics and listPipelineTransitions (ADMIN, rate-limited).

Example

Move a deal to another stage:
Full variable schemas, response shapes, and worked examples for every operation are available from the discovery endpoint.