Deals
`/deals`
One page of records, newest first unless you say otherwise, with the total count in meta so you know how far to paginate.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
page?integer1-based. meta.totalPages says how many there are.
1 <= value1per_page?integerRows per page. A value above 200 returns 400 - never a silent clamp.
1 <= value <= 20050sort?stringPrefix with - for descending. An undeclared sort returns 400.
"-updatedAt""createdAt""-createdAt""updatedAt""-updatedAt""valueCents""-valueCents""name""-name"q?stringCase-insensitive "contains", across: name.
filter[status]?stringExact match on status.
"open""won""lost"filter[clientId]?stringExact match on clientId.
The requested page.
application/json- response
data*array<>meta*curl -X GET 'https://api.usedashly.com/v1/deals'{ "data": [ { "id": "string", "clientId": "string", "name": "string", "valueCents": 0, "status": "open", "notes": "string", "expectedCloseAt": "2019-08-24T14:15:22Z", "wonAt": "2019-08-24T14:15:22Z", "lostAt": "2019-08-24T14:15:22Z", "lostReasonId": "string", "lostReasonLabel": "string", "projectId": "string", "plannedProjectId": "string", "revenueKind": "one_shot", "recurrencePeriod": "monthly", "recurrenceStartKind": "string", "recurrenceStartsOn": "2019-08-24", "recurrenceStartMilestoneId": "string", "recurrenceEndsOn": "2019-08-24", "commitmentMonths": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "amountCents": 0, "partAmountCents": 0, "customFields": {} } ], "meta": { "page": 0, "perPage": 0, "total": 0, "totalPages": 0 }}Links are given as the target's public id (clientId: "hsbftmp3f5"); the API resolves them server-side. Fields the database requires but the interface decides for you are filled in the same way here.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
name*string1 <= length <= 200valueCents?|nullnotes?string|nullexpectedCloseAt?string|nullclientId?string|nullcontactId?string|nullstageId?string|nullcustomFields?revenueKind?string"one_shot""recurring"recurrencePeriod?|nullrecurrenceStartKind?|nullrecurrenceStartsOn?|nullrecurrenceStartMilestoneId?|nullrecurrenceEndsOn?|nullcommitmentMonths?|nullcreatedAt?stringWhen this actually happened, for an import. Past dates only; defaults to now. updatedAt follows it unless the body sets one.
date-timeCreated. The body is the new record, as a read would return it.
application/json- response
data*curl -X POST 'https://api.usedashly.com/v1/deals' \ -H 'Content-Type: application/json' \ -d '{ "name": "string"}'{ "data": { "id": "string", "clientId": "string", "name": "string", "valueCents": 0, "status": "open", "notes": "string", "expectedCloseAt": "2019-08-24T14:15:22Z", "wonAt": "2019-08-24T14:15:22Z", "lostAt": "2019-08-24T14:15:22Z", "lostReasonId": "string", "lostReasonLabel": "string", "projectId": "string", "plannedProjectId": "string", "revenueKind": "one_shot", "recurrencePeriod": "monthly", "recurrenceStartKind": "string", "recurrenceStartsOn": "2019-08-24", "recurrenceStartMilestoneId": "string", "recurrenceEndsOn": "2019-08-24", "commitmentMonths": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "amountCents": 0, "partAmountCents": 0, "customFields": {} }}The full record, custom fields included when the resource carries them. A record from another agency is a 404, not a 403 - its existence is not ours to confirm.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe record's public id (hsbftmp3f5), as returned in the id field. An internal UUID returns 404.
Found.
application/json- response
data*curl -X GET 'https://api.usedashly.com/v1/deals/string'{ "data": { "id": "string", "clientId": "string", "name": "string", "valueCents": 0, "status": "open", "notes": "string", "expectedCloseAt": "2019-08-24T14:15:22Z", "wonAt": "2019-08-24T14:15:22Z", "lostAt": "2019-08-24T14:15:22Z", "lostReasonId": "string", "lostReasonLabel": "string", "projectId": "string", "plannedProjectId": "string", "revenueKind": "one_shot", "recurrencePeriod": "monthly", "recurrenceStartKind": "string", "recurrenceStartsOn": "2019-08-24", "recurrenceStartMilestoneId": "string", "recurrenceEndsOn": "2019-08-24", "commitmentMonths": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "amountCents": 0, "partAmountCents": 0, "customFields": {} }}A partial update: only the fields you send change. One exception - customFields is replaced wholesale, not merged, so sending it with a single key clears the others. Read the record, merge, then write.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe record's public id (hsbftmp3f5), as returned in the id field. An internal UUID returns 404.
application/json- body
name?string1 <= length <= 200valueCents?|nullnotes?string|nullexpectedCloseAt?string|nullclientId?string|nullcontactId?string|nullstageId?string|nullcustomFields?revenueKind?string"one_shot""recurring"recurrencePeriod?|nullrecurrenceStartKind?|nullrecurrenceStartsOn?|nullrecurrenceStartMilestoneId?|nullrecurrenceEndsOn?|nullcommitmentMonths?|nullUpdated. The body is the record as it now stands.
application/json- response
data*curl -X PATCH 'https://api.usedashly.com/v1/deals/string' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": { "id": "string", "clientId": "string", "name": "string", "valueCents": 0, "status": "open", "notes": "string", "expectedCloseAt": "2019-08-24T14:15:22Z", "wonAt": "2019-08-24T14:15:22Z", "lostAt": "2019-08-24T14:15:22Z", "lostReasonId": "string", "lostReasonLabel": "string", "projectId": "string", "plannedProjectId": "string", "revenueKind": "one_shot", "recurrencePeriod": "monthly", "recurrenceStartKind": "string", "recurrenceStartsOn": "2019-08-24", "recurrenceStartMilestoneId": "string", "recurrenceEndsOn": "2019-08-24", "commitmentMonths": 0, "createdAt": "2019-08-24T14:15:22Z", "updatedAt": "2019-08-24T14:15:22Z", "amountCents": 0, "partAmountCents": 0, "customFields": {} }}Permanent. The audit log keeps the trace; the record does not come back.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe record's public id (hsbftmp3f5), as returned in the id field. An internal UUID returns 404.
Deleted. Empty body.
curl -X DELETE 'https://api.usedashly.com/v1/deals/string'Every verb this resource answers to, with its target and the JSON Schema of its body - the same contracts this document describes, readable at runtime.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
The available verbs.
application/json- response
data*array<>curl -X GET 'https://api.usedashly.com/v1/deals/actions'{ "data": [ { "name": "string", "label": "string", "description": "string", "target": "item", "readOnly": true, "path": "string", "input": {} } ]}Wins, loses or reopens the deal without moving it between stages. Winning signs the organisation and opens the delivery project (or attaches one of the client's existing projects via attachProject, adding the deal to its roadmap as a block named, dated and priced by block), and may open that project to the deal's delivery partners via sharePartners; losing requires a reason from the catalogue, given by its label.
Does what the dashboard's closeDealAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
outcome*string"won""lost""reopen"reason?stringlength <= 120note?stringlength <= 1000attachProject?stringlength <= 40sharePartners?array<>items <= 20block?Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/close' \ -H 'Content-Type: application/json' \ -d '{ "outcome": "won"}'{ "data": null}Recreates a qualified lead from the deal - organisation, contact, notes - then archives the deal, so the pipeline keeps the history of what was attempted.
Does what the dashboard's convertDealToLeadAction does - same implementation, so the two cannot diverge. Takes no body.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/convert-to-lead'{ "data": null}Copies the deal into a new opportunity on the same organisation, carrying value, contact, buying committee and product lines. The copy starts again at the pipeline's first stage.
Does what the dashboard's duplicateDealAction does - same implementation, so the two cannot diverge. Takes no body.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/duplicate'{ "data": null}Merges this deal into the target deal: activities, notes, product lines and buying committee move across, then this deal is deleted.
Does what the dashboard's mergeDealsAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
targetDealId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/merge' \ -H 'Content-Type: application/json' \ -d '{ "targetDealId": "string"}'{ "data": null}Archives the deal - it leaves the board without losing its history - or restores it when archived is false.
Does what the dashboard's setDealArchivedAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
archived*booleanDone.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/set-archived' \ -H 'Content-Type: application/json' \ -d '{ "archived": true}'{ "data": null}Reassigns sales ownership of the deal to an agency member (see /v1/members), or clears it with ownerId: null.
Does what the dashboard's setDealOwnerAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
ownerId?|nullDone.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/set-owner' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": null}Attaches an existing contact to the deal's buying committee with their weight (decision-maker, influencer, participant), or updates that weight if they are already on it.
Does what the dashboard's upsertDealContactAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
contactId*string1 <= length <= 60role*string"decision_maker""influencer""participant"Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/upsert-contact' \ -H 'Content-Type: application/json' \ -d '{ "contactId": "string", "role": "decision_maker"}'{ "data": null}Removes a contact from the deal's buying committee. The contact record itself is kept.
Does what the dashboard's removeDealContactAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
contactId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/remove-contact' \ -H 'Content-Type: application/json' \ -d '{ "contactId": "string"}'{ "data": null}Appends a line to what the deal sells: name, quantity and unit price in cents.
Does what the dashboard's addDealProductAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
name*string1 <= length <= 200quantity?number0 < value <= 10000001unitAmountCents?integer0 <= value <= 90071992547409910Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/add-product' \ -H 'Content-Type: application/json' \ -d '{ "name": "string"}'{ "data": null}One sentence about an organisation becomes the right record: an unknown organisation is created with a lead to contact; a client gets a deal in the pipeline for existing clients; anyone else a deal in the default pipeline. A follow-up task is always planned for the owner (default: in 3 days). 409 when the organisation already has an open deal, unless onExistingDeal is create. Never creates a project.
Does what the dashboard's createOpportunityAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
clientId?string1 <= length <= 60organisationName?string2 <= length <= 120summary*string1 <= length <= 200amountCents?|nullfollowUpOn?string^\d{4}-\d{2}-\d{2}$ownerId?string1 <= length <= 120onExistingDeal?string"fail""fail""create"Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/actions/new-opportunity' \ -H 'Content-Type: application/json' \ -d '{ "summary": "string"}'{ "data": null}Removes a line from what the deal sells, addressed by its public id. List the lines with /v1/deal-products?filter[dealId]=….
Does what the dashboard's removeDealProductAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
lineId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/remove-product' \ -H 'Content-Type: application/json' \ -d '{ "lineId": "string"}'{ "data": null}Links a quote of the agency's Pennylane account (quoteId, Pennylane's id) to this deal. The quote is read from Pennylane with the agency's key: one that key does not reach answers 404; no Pennylane connection answers 422 not_connected. A deal can hold several quotes and linking the same pair again only refreshes its stored number, label, amount and status. Returns linked (false when it already was) and the quote as Pennylane gave it.
Does what the dashboard's linkDealPennylaneQuoteAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
quoteId*integer0 < value <= 9007199254740991Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/link-pennylane-quote' \ -H 'Content-Type: application/json' \ -d '{ "quoteId": 1}'{ "data": null}Removes the link between this deal and a Pennylane quote (quoteId). Nothing changes in Pennylane, and it needs no Pennylane connection. Unlinking a pair that was never linked does nothing (unlinked: false).
Does what the dashboard's unlinkDealPennylaneQuoteAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
quoteId*integer0 < value <= 9007199254740991Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/unlink-pennylane-quote' \ -H 'Content-Type: application/json' \ -d '{ "quoteId": 1}'{ "data": null}Creates a relation between this record and a target object (targetType plus the target's public targetId) in the relation graph. Linking the same pair twice does nothing.
Does what the dashboard's linkObjectAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
targetType*string"account""contact""project""ticket""deal""user""proposal"targetId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/link-object' \ -H 'Content-Type: application/json' \ -d '{ "targetType": "account", "targetId": "string"}'{ "data": null}Removes the relation between this record and the target object in the relation graph. Unlinking a pair that was never linked does nothing. A deal/project pair is unlinked like unlink-project on the deal: the change is audited, so the key must be attached to a user (403 with reason key_not_attached otherwise).
Does what the dashboard's unlinkObjectAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
targetType*string"account""contact""project""ticket""deal""user""proposal"targetId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/unlink-object' \ -H 'Content-Type: application/json' \ -d '{ "targetType": "account", "targetId": "string"}'{ "data": null}Links this deal to its delivery project (projectId, public id). A deal has one project, of the same client (409 deal_has_project, 400 deal_project_other_client); linking the same pair again changes nothing. If the project is already running (active) and the deal still open, the deal is marked won. Returns wonDeal.
Does what the dashboard's linkObjectAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
projectId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/link-project' \ -H 'Content-Type: application/json' \ -d '{ "projectId": "string"}'{ "data": null}Removes the link between this deal and the project (projectId, public id). Neither record's status changes — a deal won because its project started stays won. Unlinking a pair that was never linked does nothing.
Does what the dashboard's unlinkObjectAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
projectId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/unlink-project' \ -H 'Content-Type: application/json' \ -d '{ "projectId": "string"}'{ "data": null}Sets the existing project (projectId, public id; null clears it) this deal joins when it is won: winning it then creates no project, links the deal to that one and adds a client-visible roadmap milestone named after the deal. The project must be live delivery (active or proposal, else 400 deal_planned_project_closed) of the deal's own client (400 deal_project_other_client); a deal that already has its project answers 409 deal_has_project. Read back as plannedProjectId.
Does what the dashboard's setDealPlannedProjectAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
projectId*|nullDone.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/set-planned-project' \ -H 'Content-Type: application/json' \ -d '{ "projectId": "string"}'{ "data": null}Attaches an invoice of the agency's Pennylane mirror to the deal it bills: pennylaneId (Pennylane's id) or invoiceId (as projects › deals returns it), exactly one. Only an invoice of the deal's own client (400 invoice_deal_other_client); a quote or an unknown id answers 404. An invoice attached to another deal moves to this one; attaching it again changes nothing (changed: false). Nothing is written in Pennylane.
Does what the dashboard's linkDealInvoiceAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
pennylaneId?integer0 < value <= 9007199254740991invoiceId?string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/link-invoice' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": null}Detaches an invoice (pennylaneId or invoiceId, exactly one) from this deal. An invoice attached to another deal, or to none, is left alone (changed: false). Nothing is written in Pennylane.
Does what the dashboard's unlinkDealInvoiceAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
pennylaneId?integer0 < value <= 9007199254740991invoiceId?string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/unlink-invoice' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": null}From effectiveFrom (YYYY-MM-DD) on, the recurring deal bills amountCents per period (excl. tax) (e.g. +200 € a month from March) without a new deal. One step per day: the same day again changes its amount (changed: false when it already was). A step overrides the deal's base amount from its day on. A one-shot deal answers 409 deal_not_recurring.
Does what the dashboard's setRecurrenceAmountAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
effectiveFrom*string^\d{4}-\d{2}-\d{2}$amountCents*integer0 <= value <= 2000000000Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/set-recurrence-amount' \ -H 'Content-Type: application/json' \ -d '{ "effectiveFrom": "string", "amountCents": 0}'{ "data": null}Removes the step of effectiveFrom (YYYY-MM-DD); changed: false when the deal had none that day. The amount then in force is the previous step's, else the deal's base amount.
Does what the dashboard's removeRecurrenceAmountAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
effectiveFrom*string^\d{4}-\d{2}-\d{2}$Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/remove-recurrence-amount' \ -H 'Content-Type: application/json' \ -d '{ "effectiveFrom": "string"}'{ "data": null}The "+ Option → new recurring deal" gesture: creates a small recurring deal of the same client and period, on the agency's follow-up pipeline (no new onboarding), planned to join this deal's project at its win when that project is live, named name (default <deal> — option), worth amountCents per period. For an option that needs its own quote and signature; a change of amount on this deal is set-recurrence-amount. A one-shot deal answers 409 deal_not_recurring. Returns the new deal's public id.
Does what the dashboard's addRecurringOptionAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
name?string1 <= length <= 200amountCents?|nullDone.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/add-option' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": null}What this recurring deal is due in the month, what is already invoiced and what is missing; an empty rows when it is not won, not recurring, not started or ended. Amounts are excl. tax: dueCents (the amount in force; a quarterly, half-yearly or yearly deal is due in full in the months its period starts, counted from its start), invoicedCents (its attached invoices issued that month, excl. tax) and missingCents (never below zero). month is YYYY-MM, this month by default. Read-only: nothing is written to Pennylane.
Reads the same data as the in-app listToInvoice - same implementation. Changes nothing; also answers GET with the same fields as query parameters.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
month?string^\d{4}-(0[1-9]|1[0-2])$The figures.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X GET 'https://api.usedashly.com/v1/deals/string/actions/to-invoice'{ "data": null}What this recurring deal is due in the month, what is already invoiced and what is missing; an empty rows when it is not won, not recurring, not started or ended. Amounts are excl. tax: dueCents (the amount in force; a quarterly, half-yearly or yearly deal is due in full in the months its period starts, counted from its start), invoicedCents (its attached invoices issued that month, excl. tax) and missingCents (never below zero). month is YYYY-MM, this month by default. Read-only: nothing is written to Pennylane.
Reads the same data as the in-app listToInvoice - same implementation. Changes nothing; also answers GET with the same fields as query parameters.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
month?string^\d{4}-(0[1-9]|1[0-2])$Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/to-invoice' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": null}Every won recurring deal of the agency due or invoiced in the month, the largest missing amount first, with the totals (what the Today page's invoicing widget shows). Amounts are excl. tax: dueCents (the amount in force; a quarterly, half-yearly or yearly deal is due in full in the months its period starts, counted from its start), invoicedCents (its attached invoices issued that month, excl. tax) and missingCents (never below zero). month is YYYY-MM, this month by default. Read-only: nothing is written to Pennylane.
Reads the same data as the in-app listToInvoice - same implementation. Changes nothing; also answers GET with the same fields as query parameters.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
month?string^\d{4}-(0[1-9]|1[0-2])$The figures.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X GET 'https://api.usedashly.com/v1/deals/actions/to-invoice-all'{ "data": null}Every won recurring deal of the agency due or invoiced in the month, the largest missing amount first, with the totals (what the Today page's invoicing widget shows). Amounts are excl. tax: dueCents (the amount in force; a quarterly, half-yearly or yearly deal is due in full in the months its period starts, counted from its start), invoicedCents (its attached invoices issued that month, excl. tax) and missingCents (never below zero). month is YYYY-MM, this month by default. Read-only: nothing is written to Pennylane.
Reads the same data as the in-app listToInvoice - same implementation. Changes nothing; also answers GET with the same fields as query parameters.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
month?string^\d{4}-(0[1-9]|1[0-2])$Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/actions/to-invoice-all' \ -H 'Content-Type: application/json' \ -d '{}'{ "data": null}Splits this deal into parts in one transaction: its project is reused (the planned one, else the linked one) or created as a proposal for the deal's client, one roadmap milestone per one-shot row, one deal per ticked row. Row 0 may be this deal itself (isSource: true, its kind kept; its milestone reused). Each row of rows (1 to 20) is a part: name, kind (one_shot | recurring), amountCents (excl. tax; per period when recurring), createDeal (true: a deal now on the follow-up pipeline; false: a planned milestone holding the amount as its estimate for a one-shot row, nothing stored yet for a recurring row, returned in skipped). A one-shot row is a roadmap milestone: startsOn, endsOn (YYYY-MM-DD) and precision (day | month | quarter | half) together, or none. A recurring row takes period (default monthly), start ({kind: on_win}, {kind: date, on} or {kind: after_row, row} naming a one-shot row of the same body by its index) and commitmentMonths. New deals belong to the same client and contact, are planned to join the project, and are expected to close when their milestone (or their recurrence) starts. When the agency has several follow-up pipelines, name one by its public id in followUpPipelineId (refusal follow_up_pipeline_required lists them); with none, the refusal is no_follow_up_pipeline. roadmapClientVisible: true (the 'show the roadmap to the client' box) writes the milestones visible in the client's roadmap; absent or false, they stay internal until the agency shows them. The same idempotencyKey sent again answers the first result (replayed: true); with another body it answers 409 split_key_reused. Needs projects:write as well. Returns the project, deals and milestones by public id.
Does what the dashboard's splitIntoPartsAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
rows*array<>1 <= items <= 20followUpPipelineId?|nullidempotencyKey*string^[A-Za-z0-9_.:-]{8,255}$roadmapClientVisible?boolean|nullDone.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/split' \ -H 'Content-Type: application/json' \ -d '{ "rows": [ { "name": "string", "kind": "one_shot", "createDeal": true } ], "idempotencyKey": "string"}'{ "data": null}Invites email into the client portal of this deal's organisation, whether it is still a prospect or already a client: the same portal, with the same sections and visibility rules. Writes a pending invitation (as POST /v1/portal-invitations does) and mails its link to a signed client's people only: while Dashly sends no mail to leads and prospects (owner decision 2026-10-22, the prospectEmails switch), an organisation that is not a signed client (prospect, lost) is NOT mailed, and the response carries the join link in invitationUrl for the agency to send itself (mailed: false); a client's answer has mailed: true and invitationUrl: null. roleKey is client_member (default) or client_admin, and name names the person when the address is new to the organisation (the CRM person is found or created, never duplicated). A deal without organisation answers 422 portal_deal_no_client. Needs clients:write as well. Returns the client by its public id, the invitation's address, role and status, mailed and invitationUrl.
Does what the dashboard's invitePortalAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
email*string^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$emaillength <= 200roleKey?string"client_member""client_member""client_admin"name?stringlength <= 120Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/invite-portal-member' \ -H 'Content-Type: application/json' \ -d '{ "email": "user@example.com"}'{ "data": null}Closes the client portal of this deal's organisation once EVERY deal of it is lost and it is still a prospect: in one transaction, every portal member is removed and every pending invitation cancelled (their logins and CRM records stay). Refused with 409 portal_revoke_deal_open while a deal of the organisation is open or won, 409 portal_revoke_not_prospect for a signed client (closed member by member on clients), 422 portal_deal_no_client for a deal without organisation. Running it again revokes nothing more. Needs clients:write as well. Returns the client by its public id and the addresses removed and cancelled.
Does what the dashboard's revokeDealPortalAccessAction does - same implementation, so the two cannot diverge. Takes no body.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/revoke-portal-access'{ "data": null}Answers whether this deal is shown in its organisation's client portal (visible, false until the agency switches it on) and whether its amounts are hidden there (hideAmount). installed: false while the feature's migration is not applied (the deal is then hidden). Read only.
Reads the same data as the in-app setDealPortalVisibilityAction - same implementation. Changes nothing; also answers GET with the same fields as query parameters. Takes no body.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
The figures.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X GET 'https://api.usedashly.com/v1/deals/string/actions/portal-visibility'{ "data": null}Answers whether this deal is shown in its organisation's client portal (visible, false until the agency switches it on) and whether its amounts are hidden there (hideAmount). installed: false while the feature's migration is not applied (the deal is then hidden). Read only.
Reads the same data as the in-app setDealPortalVisibilityAction - same implementation. Changes nothing; also answers GET with the same fields as query parameters. Takes no body.
Required scope: deals:read.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/portal-visibility'{ "data": null}Shows this deal in its organisation's client portal (visible: true) or hides it (false, the default for every deal): once shown, the organisation's members holding portal.deals.read see its project's roadmap — each part with a client-readable status (under discussion, accepted, declined; never the pipeline stage), the recurring parts with their start, the recap, the client-visible next steps and the team on the project. hideAmount: true leaves every amount and the recap out of what the portal receives. Both switches are written together. A deal without organisation answers 422 portal_deal_no_client; before the feature's migration, 409 deal_portal_not_installed. Needs clients:write as well. Returns the deal by its public id and both switches.
Does what the dashboard's setDealPortalVisibilityAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
visible*booleanhideAmount?booleanfalseDone.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/set-portal-visibility' \ -H 'Content-Type: application/json' \ -d '{ "visible": true}'{ "data": null}Moves the deal to another sales pipeline. The destination stage is required and must belong to the target pipeline - stages do not map from one pipeline to another.
Does what the dashboard's moveDealToPipelineAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
pipelineId*string1 <= length <= 60stageId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/move-to-pipeline' \ -H 'Content-Type: application/json' \ -d '{ "pipelineId": "string", "stageId": "string"}'{ "data": null}Makes this contact the deal's primary contact, adding them to the buying committee if they were not on it. Their weight on the committee is left alone.
Does what the dashboard's setDealPrimaryContactAction does - same implementation, so the two cannot diverge.
Required scope: deals:write.
bearerAuthAuthorizationBearer <token>Your agency's API key: Authorization: Bearer ak_…. Created in Connectors → API & webhooks and shown once. A key authenticates an agency, not a person.
id*stringThe public id of the record to act on. It is resolved inside your agency before the action runs, so an id from another tenant is a 404 and never reaches it.
Idempotency-Key?stringA value you choose (a UUID is the usual one), 8 to 255 characters of A-Z a-z 0-9 _ . : -. Retrying with the same key returns the first call's answer instead of creating a second record, for seven days. The same key with a different body returns 409.
8 <= length <= 255application/json- body
contactId*string1 <= length <= 60Done.
application/json- response
data*unknownThe action's result; its shape depends on the verb.
curl -X POST 'https://api.usedashly.com/v1/deals/string/actions/set-primary-contact' \ -H 'Content-Type: application/json' \ -d '{ "contactId": "string"}'{ "data": null}