Creating and updating data

Changes go through mutations. Every object has a create and an update mutation that work the same way, and deleting is an update too. Changes made through the API show up in the app straight away, for everyone on the team.

Create an item

Create mutations are named create plus the object: createTodo, createIssue, createRock. The new item's fields go inside input, under the object's name, and you choose which fields of the new item to get back:

GraphQL
mutation AddTodo($todo: TodoInput!) {
  createTodo(input: { todo: $todo }) {
    todo {
      id
      name
      dueDate
    }
  }
}
JSON
{
  "todo": {
    "name": "Send the Q4 board pack",
    "desc": "",
    "teamId": "0b7e5f6a-3c2d-4e1f-9a8b-7c6d5e4f3a21",
    "userId": "5f2d8c4b-1a3e-4c7d-b9f0-2e6a7d8c9b10",
    "todoStatusId": "TODO",
    "priorityNo": 999,
    "dueDate": "2026-11-20",
    "companyId": "6a1d4e2b-7c3f-4a8e-b5d9-0f1e2d3c4b5a"
  }
}

A few things every create needs:

  • companyId on every new item. Get it once with query { currentCompanyId } or from the API Keys page.
  • The owner and team, as IDs (userId, teamId). Look them up with users and teams queries.
  • The object's required fields. The Data model guide lists them for each object, and the error message names any you've missed.

Leave out id, createdAt and stateId, and they're filled in for you. You can set id yourself (any UUID) when you want to refer to the new item in the same request; see Make several changes at once.

Update an item

Update mutations are named update plus the object. Pass the item's id, and in patch only the fields you want to change. Everything else stays as it is:

GraphQL
mutation MarkTodoDone($id: UUID!) {
  updateTodo(input: { id: $id, patch: { todoStatusId: "COMPLETE" } }) {
    todo { id name todoStatusId }
  }
}

Some common updates:

To do thisPatch
Mark a To-do doneupdateTodo with { todoStatusId: "COMPLETE" }
Solve an IssueupdateIssue with { issueStatusId: "COMPLETE" }
Set a Rock off-trackupdateRock with { rockStatusId: "OFFTRACK" }
Move an Issue to another teamupdateIssue with { teamId: "..." }
Change a due date{ dueDate: "2026-12-05" }
Hand an item to someone else{ userId: "..." }

When you change a status, also set statusUpdatedAt to the current time, as the app does. Success.co uses it for things like when a To-do was completed, and it isn't updated for you:

GraphQL
mutation MarkTodoDone($id: UUID!, $now: Datetime!) {
  updateTodo(input: { id: $id, patch: { todoStatusId: "COMPLETE", statusUpdatedAt: $now } }) {
    todo { id todoStatusId statusUpdatedAt }
  }
}

Delete an item

Rocks, To-dos, Issues, Headlines, Milestones, Scorecard measurables and values, comments and the other main objects don't have delete mutations. Deleting one is an update that sets stateId to DELETED, exactly what the app does when someone clicks Delete:

GraphQL
mutation DeleteIssue($id: String!) {
  updateIssue(input: { id: $id, patch: { stateId: "DELETED" } }) {
    issue { id stateId }
  }
}

The item disappears from the app but stays in the API with stateId: "DELETED", which is why list queries should filter on stateId: { equalTo: "ACTIVE" }. To restore it, set stateId back to ACTIVE.

A few linking records (such as which teams a process is shared with) do have delete mutations, and those remove the record for good.

Make several changes at once

You can put more than one mutation in a request. Give each an alias so you can tell the answers apart:

GraphQL
mutation {
  first: updateTodo(input: { id: "3f1c...", patch: { todoStatusId: "COMPLETE" } }) { todo { id } }
  second: updateTodo(input: { id: "9a4e...", patch: { todoStatusId: "COMPLETE" } }) { todo { id } }
}

The mutations in one request run as a single unit: if any of them fails, none of them are saved. That makes it safe to create things that belong together, like a Rock and its link to a team. Choose the Rock's id yourself (a fresh UUID) so the second mutation can refer to it:

GraphQL
mutation AddRock($rockId: UUID!, $teamId: UUID!, $userId: UUID!, $companyId: UUID!) {
  createRock(
    input: {
      rock: {
        id: $rockId
        name: "Launch the partner program"
        desc: ""
        type: "company"
        rockStatusId: "ONTRACK"
        dueDate: "2026-12-31"
        userId: $userId
        companyId: $companyId
      }
    }
  ) {
    rock { id }
  }
  createTeamsOnRock(
    input: { teamsOnRock: { rockId: $rockId, teamId: $teamId, companyId: $companyId } }
  ) {
    teamsOnRock { id }
  }
}

In JavaScript, crypto.randomUUID() makes a UUID; in Python, str(uuid.uuid4()).

Who made the change

Changes are made as the person who owns the API key. The app shows them as that person's, and lastUpdatedByUserId on the item records it. If your integration makes a lot of changes, consider creating a separate Success.co user for it (for example "Finance sync", which counts as a user on your plan) and making its key there, so its changes are easy to tell apart from yours. It also keeps the integration running if you leave: a key stops working when its owner is deactivated, so an integration that runs on a person's key stops when they do. Keep that user active for as long as the integration runs.

Test on a copy first. There's no undo for changes made through the API, apart from setting them back yourself. Try new scripts against a test company, or on a team set up for testing, before pointing them at your real data.