Skip to content
  • There are no suggestions because the search field is empty.

Accord Developer API (Guide)

Accord API Guide for common Summary update workflows – the same patterns can be repurposed for other parts of an Accord.

Table of Contents

  1. Overview

  2. Create an accord from a template (playbook)

  3. Get an Accord by ID

  4. Find an existing accord by account, opportunity, or point person

  5. Get summaries by accord ID

  6. Get sections for a summary

  7. Get a section for a summary matching a given title

  8. Update a section

  9. End-to-end example with cURL

  10. Error handling

Overview

This article acts as a detailed guide, explaining how to locate and modify Accord Summaries. For additional information on the Accord Developer API, please see the accompanying article, Accord Developer API (Overview)

1. Create an accord from a template (playbook)

In Accord, a template is just an Accord with isTemplate: true. To spin up a new accord from one, use the duplicateAccord mutation. It clones the template’s stages, steps, summaries, sections, and resources into a fresh accord.

Mutation

mutation CreateAccordFromTemplate(
  $accordId: String!
  $workspaceId: String
  $ownerEmail: String
) {
  duplicateAccord(
    input: {
      accordId: $accordId
      workspaceId: $workspaceId
      ownerEmail: $ownerEmail
      style: "from-template"
    }
  ) {
    accordId
    accord {
      id
      accountName
      opportunityName
      createdFromTemplateId
      workspaceId
      createdAt
    }
  }
}

Variables

Variable Type Required Description
accordId String! Yes The ID of the template accord (the one with isTemplate: true) you want to clone.
workspaceId String No Workspace to create the new accord in. Defaults to the template’s workspace.
ownerEmail String No Email of the workspace user who should own the new accord. Defaults to the caller.

Example variables

{
"accordId": "f1e2d3c4-b5a6-4789-0123-456789abcdef",
"ownerEmail": "ae@yourcompany.com"
}

Tip — finding template IDs

If you don’t have the template ID handy, list them with:

query ListTemplates {
accords(
filter: { isTemplate: { equalTo: true }, deletedAt: { isNull: true } }
orderBy: [TEMPLATE_NAME_ASC]
) {
id
templateName
workspaceId
}
}

2. Get an accord by ID

The simplest read in the API. Use the singular accord query when you already know the ID.

Query

query GetAccordById($id: String!) {
accord(id: $id) {
id
accountName
opportunityName
opportunityAmount
closeDate
crmId
crmType
pointPersonWorkspaceAccountId
pointPersonName
status
progress
createdFromTemplateId
workspaceId
createdAt
updatedAt
}
}

Variables

{ "id": "a1b2c3d4-e5f6-4789-0123-456789abcdef" }

If no accord matches the ID (or it has been deleted), accord returns null.

3. Find an existing accord by account, opportunity, or point person

The accords list query takes a rich filter argument. You can match any combination of accountName, crmId (the CRM opportunity / deal ID), and pointPersonWorkspaceAccountId. Combine clauses with and for AND semantics, or or for OR semantics.

Naming note: in the Accord schema, crmId is the ID of the linked CRM opportunity / deal (e.g. a Salesforce Opportunity ID or HubSpot Deal ID). accountName is the customer company name. pointPersonWorkspaceAccountId is the workspace user assigned as point person.

Query

query FindAccord(
$accountName: String
$crmId: String
$pointPersonWorkspaceAccountId: String
) {
accords(
filter: {
and: [
{ isTemplate: { equalTo: false } }
{ deletedAt: { isNull: true } }
{ accountName: { equalTo: $accountName } }
{ crmId: { equalTo: $crmId } }
{ pointPersonWorkspaceAccountId: { equalTo: $pointPersonWorkspaceAccountId } }
]
}
orderBy: [UPDATED_AT_DESC]
first: 20
) {
id
accountName
opportunityName
crmId
crmType
pointPersonWorkspaceAccountId
pointPersonName
status
updatedAt
}
}

How it behaves

  • equalTo: null (i.e. omitting the variable) matches only records whose value is also null. So if you want a clause to be optional, simply remove it from the and array rather than passing null.
  • To match any one of several values, swap equalTo for in: ["...", "..."].
  • accountName is a case-sensitive exact match. For fuzzy matching use includesInsensitive instead of equalTo.

Examples

By account only:

{ "accountName": "Acme Corp" }
filter: {
and: [
{ isTemplate: { equalTo: false } }
{ deletedAt: { isNull: true } }
{ accountName: { equalTo: $accountName } }
]
}

By CRM opportunity / deal ID only (most reliable, since CRM IDs are unique):

filter: {
and: [
{ deletedAt: { isNull: true } }
{ crmId: { equalTo: $crmId } }
]
}

By point person + account:

filter: {
and: [
{ isTemplate: { equalTo: false } }
{ deletedAt: { isNull: true } }
{ accountName: { equalTo: $accountName } }
{ pointPersonWorkspaceAccountId: { equalTo: $pointPersonWorkspaceAccountId } }
]
}

4. Get summaries by accord ID

Each accord has zero or more Summary records (the tabs/pages of the customer-facing experience). Use the summaries list query, filtered by accordId.

Query

query GetSummariesByAccord($accordId: String!) {
summaries(
filter: {
accordId: { equalTo: $accordId }
deletedAt: { isNull: true }
}
orderBy: [ORDER_ASC]
) {
id
title
order
internal
bannerImageUrl
accordId
workspaceId
createdAt
updatedAt
}
}

Variables

{ "accordId": "a1b2c3d4-e5f6-4789-0123-456789abcdef" }

The result is an array of summaries ordered by their display order. Set internal: false in the filter if you only want customer-visible summaries.

5. Get sections for a summary

Each summary contains an ordered list of Section records (text blocks, picklists, mutual action plans, etc.). Filter the sections query by summaryId.

Query

query GetSectionsBySummary($summaryId: String!) {
sections(
filter: {
summaryId: { equalTo: $summaryId }
deletedAt: { isNull: true }
}
orderBy: [ORDER_ASC]
) {
id
title
type
order
data
internal
summaryId
workspaceId
createdAt
updatedAt
}
}

Variables

{ "summaryId": "11111111-2222-3333-4444-555555555555" }

The data field is a JSON blob whose shape depends on type (text editor content, picklist selections, etc.). It’s returned as-is — your client should branch on type when interpreting it.

Bonus — fetch summaries and their sections in one round trip

Because the schema exposes nested relationships, you can grab everything for an accord in a single call:

query AccordWithSummariesAndSections($accordId: String!) {
accord(id: $accordId) {
id
accountName
summaries(
filter: { deletedAt: { isNull: true } }
orderBy: [ORDER_ASC]
) {
id
title
order
sections(
filter: { deletedAt: { isNull: true } }
orderBy: [ORDER_ASC]
) {
id
title
type
order
data
}
}
}
}

6. Get a section for a summary matching a given title

Same query as above, with an extra title clause. Section titles are not guaranteed to be unique within a summary, so this returns a list — usually you’ll take the first result.

Query

query GetSectionByTitle($summaryId: String!, $title: String!) {
sections(
filter: {
summaryId: { equalTo: $summaryId }
title: { equalTo: $title }
deletedAt: { isNull: true }
}
orderBy: [ORDER_ASC]
first: 1
) {
id
title
type
order
data
}
}

Variables

{
"summaryId": "11111111-2222-3333-4444-555555555555",
"title": "Goals & Success Criteria"
}

Variations

  • Case-insensitive exact match: title: { equalToInsensitive: $title }
  • Substring match: title: { includesInsensitive: $title }

7. Update a section

Section content is updated via updateSection. You provide the section’s id plus a patch object containing only the fields you want to change.

Mutation

mutation UpdateSection($id: String!, $patch: SectionPatch!) {
updateSection(input: { id: $id, patch: $patch }) {
section {
id
title
type
order
data
updatedAt
}
}
}

Variables

{
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"patch": {
"title": "Updated title",
"data": { "content": "New body content goes here" }
}
}

Editable fields on SectionPatch

Field Type Notes
title String Display title of the section.
data JSON Section payload — shape depends on type. Pass the full new value, not a partial diff.
order BigFloat Display order. Use a value between two existing siblings to reposition.
type String Section type. Generally not changed after creation.
internal Boolean Whether the section is internal-only or customer-visible.

Important: data is replaced wholesale. To make a small change, fetch the section first (query #5 or #6), modify the JSON locally, then send the full updated object back in patch.data.

End-to-end example with cURL

Look up an accord by CRM opportunity ID, fetch its first summary, find a section called “Goals”, and update its body — using only the API.

Step 1 — find the accord

curl -X POST <https://api.inaccord.com/graphql> \\
-H "authorization: Bearer$ACCORD_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"query": "query($crmId: String!) { accords(filter: { crmId: { equalTo: $crmId }, deletedAt: { isNull: true } }, first: 1) { id accountName } }",
"variables": { "crmId": "0061a000003abcdAAA" }
}'

Step 2 — get summaries

curl -X POST <https://api.inaccord.com/graphql> \\
-H "authorization: Bearer$ACCORD_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"query": "query($accordId: String!) { summaries(filter: { accordId: { equalTo: $accordId }, deletedAt: { isNull: true } }, orderBy: [ORDER_ASC]) { id title } }",
"variables": { "accordId": "<ACCORD_ID_FROM_STEP_1>" }
}'

Step 3 — get the “Goals” section

curl -X POST <https://api.inaccord.com/graphql> \\
-H "authorization: Bearer$ACCORD_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"query": "query($summaryId: String!, $title: String!) { sections(filter: { summaryId: { equalTo: $summaryId }, title: { equalTo: $title }, deletedAt: { isNull: true } }, first: 1) { id data } }",
"variables": {
"summaryId": "<SUMMARY_ID_FROM_STEP_2>",
"title": "Goals"
}
}'

Step 4 — update the section

curl -X POST <https://api.inaccord.com/graphql> \\
-H "authorization: Bearer$ACCORD_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"query": "mutation($id: String!, $patch: SectionPatch!) { updateSection(input: { id: $id, patch: $patch }) { section { id title updatedAt } } }",
"variables": {
"id": "<SECTION_ID_FROM_STEP_3>",
"patch": { "data": { "content": "Land 3 enterprise pilots by Q2." } }
}
}'

Error handling

GraphQL responses always return HTTP 200 (unless transport-level errors occur). Check for an errors array in the response body:

{
"data": null,
"errors": [
{ "message": "permission denied", "path": ["updateSection"] }
]
}

Common causes:

  • permission denied — the API key lacks access to the workspace or record.
  • Cannot return null for non-nullable field — usually means the parent record was not found; check IDs.
  • Variable "$x" of required type ... was not provided — a String! variable was sent as null. Either provide a value or omit the corresponding clause from your filter.