Sequin makes it easy to write changes back to upstream APIs. Most collections that Sequin syncs are mutable. To create a record in a collection or mutate an existing one, you can use Sequin’s Collection Mutation API.

For write requests that don’t map cleanly to a collection mutation, you can use Sequin’s API proxy.

Collection Mutation API

The Collection Mutation API lets you mutate one or more records synchronously:

POST /v1/mutations/run

For creates and updates, you’ll send Sequin a partial record. For creates, the partial record contains only the data key:

PartialRecord
{
  "data": {
    "FirstName": "Paul",
    "LastName": "Atreides",
    "Email": "paul@arrakis.org"
  }
}

For updates, the partial record contains the upstream_id and data keys:

PartialRecord
{
  "upstream_id": "0031U00000Qn2ZVQAZ",
  "data": {
    "FirstName": "Paul",
    "LastName": "Atreides",
    "Email": "paul@arrakis.org"
  }
}

For deletes, you’ll send Sequin a list of upstream_ids.

Note that the shape of the data payload in creates and updates is the same shape that Sequin uses throughout the system for that collection. If ever in doubt, copy and paste the data field from a record or event and use it as the starting point for your mutation.

Create mutation

For create mutations, the request body is a CreateMutationRequest object with the following shape:

CreateMutationRequest
 {
  kind: "create";
  sync_id: string;
  collection_id: string;
  data: PartialRecord[];
  await_consumer_ids?: string[];
  await_consumers_timeout?: number;
}

Parameters

sync_id
string
required

The ID of the sync that the mutations should apply to.

collection_id
string
required

The ID of the collection that the mutations should apply to.

records
array
required

A list of one or more PartialRecord objects.

await_consumer_ids
array

A list of one or more consumer IDs. See await consumers below.

await_consumers_timeout
integer

The number of milliseconds to wait for consumers to finish processing a mutation. Defaults to 30000 (30 seconds). See await consumers below.

Update mutation

For update mutations, the request body is an UpdateMutationRequest object with the following shape:

UpdateMutationRequest
{
  kind: "update";
  sync_id: string;
  collection_id: string;
  data: PartialRecord[];
  await_consumer_ids?: string[];
  await_consumers_timeout?: number;
}
We use PATCH in all update mutations.

Parameters

sync_id
string
required

The ID of the sync that the mutations should apply to.

collection_id
string
required

The ID of the collection that the mutations should apply to.

records
array
required

A list of one or more PartialRecord objects.

await_consumer_ids
array

A list of one or more consumer IDs. See await consumers below.

await_consumers_timeout
integer

The number of milliseconds to wait for consumers to finish processing a mutation. Defaults to 30000 (30 seconds). See await consumers below.

Delete mutation

For delete mutations, the request body is a DeleteMutationRequest object with the following shape:

DeleteMutationRequest
{
  kind: "delete";
  sync_id: string;
  collection_id: string;
  upstream_ids: string[];
  await_consumer_ids?: string[];
  await_consumers_timeout?: number;
}

Parameters

sync_id
string
required

The ID of the sync that the mutations should apply to.

collection_id
string
required

The ID of the collection that the mutations should apply to.

upstream_id
array
required

A list of one or more upstream IDs.

await_consumer_ids
array

A list of one or more consumer IDs. See await consumers below.

await_consumers_timeout
integer

The number of milliseconds to wait for consumers to finish processing a mutation. Defaults to 30000 (30 seconds). See await consumers below.

Response

If the mutation succeeds, Sequin will return a JSON object with a records property containing each record:

200 OK
{
  "records": [
    {
      "sync_id": "70a313f8-7c94-43d4-8d0c-5659a52de5c4",
      "collection_id" : "salesforce:task",
      "upstream_id": "0018b000021BldZAAS",
      "upstream_updated_at": "2024-11-10T18:39:00.070453Z",
      "data": {
        "activity_date": "2023-09-12",
        "description" : "task description [ ... ] ",
        // ...
      },
      "deleted": false,
      // ...
    }
  ]
 }

If the mutation fails due to a validation error, Sequin will return a 400 Bad Request response with an error message:

400 Bad Request
{
  "error": "Error: Salesforce validation error: `Invalid email`",
  "docs": [ ... ]
}

If the mutation fails due to the upstream API timing out, Sequin will return a 504 Gateway Timeout response with an error message:

504 Gateway Timeout
{
  "error": "Error: Salesforce API timed out",
  "docs": [ ... ]
}

Awaiting consumers

By default, Sequin applies mutations to the upstream API and to your streams, then returns a response. You can specify that you want your request to also block until the mutations have been applied to one or more consumers. This is useful if you need a read-after-write (or “read your writes”) workflow. For example, you might want to create a Salesforce Contact via the Mutation API, then re-render a view that pulls it from your database.

To await consumers, you can include the optional await_consumer_ids property in your request. The value of await_consumer_ids is a list of one or more consumer IDs. You can find the ID of a consumer in the Sequin console or via the Management API.

By default, Sequin will wait for consumers for up to 30 seconds. You can specify how long you want Sequin to wait by including an optional await_consumers_timeout property in your request. The value of await_consumers_timeout is the number of milliseconds to wait for consumers to finish processing the mutations, after the API mutation has succeeded.

If Sequin times out while waiting for consumers, it will return a 500 response with an error message:

500 Internal Server Error
{
  "error": "Error: Timed out waiting for consumers: {consumer_id}",
  "docs": [ ... ]
}

If the mutation was not idempotent (e.g. a create mutation), in this instance it is not safe to retry.

Examples

Create a single record:

curl -X POST \
  https://api.sequin.io/v1/mutations/run \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer {token}' \
  -d '{
        "kind": "create",
        "sync_id": "my-sync-id",
        "collection_id": "salesforce:contact",
        "records": [
          {
            "data": {
              "FirstName": "Paul",
              "LastName": "Atreides",
              "Email": "paul@arrakis.org"
            }
          }
        ]
      }'

Create multiple records:

curl -X POST \
  https://api.sequin.io/v1/mutations/run \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer {token}' \
  -d '{
        "kind": "create",
        "sync_id": "my-sync-id",
        "collection_id": "salesforce:contact",
        "records": [
          {
            "data": {
              "FirstName": "Paul",
              "LastName": "Atreides",
              "Email": "paul@arrakis.org"
            }
          },
          {
            "data": {
              "FirstName": "Duncan",
              "LastName": "Idaho",
              "Email": "duncan@arrakis.org"
            }
          }
        ]
      }'

Update a single record:

curl -X POST \
  https://api.sequin.io/v1/mutations/run \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer {token}' \
  -d '{
        "kind": "update",
        "sync_id": "my-sync-id",
        "collection_id": "salesforce:contact",
        "records": [
          {
            "upstream_id": "0031U00000Qn2ZVQAZ",
            "data": {
              "FirstName": "Paul",
              "LastName": "Atreides",
              "Email": "paul@arrakis.org"
            }
          }
        ]
      }'

Update multiple records:

curl -X POST \
  https://api.sequin.io/v1/mutations/run \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer {token}' \
  -d '{
        "kind": "update",
        "sync_id": "my-sync-id",
        "collection_id": "salesforce:contact",
        "records": [
          {
            "upstream_id": "0031U00000Qn2ZVQAZ",
            "data": {
              "FirstName": "Paul",
              "LastName": "Atreides",
              "Email": "paul@arrakis.org"
            }
          },
          {
            "upstream_id": "0031U00000Qn2ZVQBA",
            "data": {
              "FirstName": "Duncan",
              "LastName": "Idaho",
              "Email": "duncan@arrakis.org"
            }
          }
        ]
      }'

Delete a single record:

curl -X POST \
  https://api.sequin.io/v1/mutations/run \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer {token}' \
  -d '{
        "kind": "delete",
        "sync_id": "my-sync-id",
        "collection_id": "salesforce:contact",
        "upstream_ids": [
          "0031U00000Qn2ZVQAZ"
        ]
      }'

Delete multiple records:

curl -X POST \
  https://api.sequin.io/v1/mutations/run/delete \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer {token}' \
  -d '{
        "kind": "delete",
        "sync_id": "my-sync-id",
        "collection_id": "salesforce:contact",
        "upstream_ids": [
          "0031U00000Qn2ZVQAZ",
          "0031U00000Qn2ZVQBA"
        ]
      }'

API proxy

The API proxy lets you make arbitrary requests to the upstream API. It’s useful for mutation requests that don’t map cleanly to a collection mutation. You can also use it for making one-off fetch requests against the upstream API.

When you use the API proxy, Sequin will authenticate your request and pace it to ensure that it doesn’t exceed rate limits.

[GET | POST | PUT | PATCH | DELETE] /v1/proxy/:sync_id/:path

The parameters in the request:

  • sync_id (required): The ID of the sync that the request belongs to.
  • path (required): The path of the request, according to the upstream API. For example, /contacts/839171.

The request body and headers are passed through to the upstream API. Sequin will augment the request with necessary authentication headers.

Examples

POST a change to the API:

curl -X POST \
  https://api.sequin.io/v1/proxy/sync-67b58087/api.stripe.com/v1/payment_intents/pm_1234/cancel \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "cancellation_reason": "requested_by_customer"
  }'

PUT a change to the API:

curl -X PUT \
  https://api.sequin.io/v1/proxy/sync-67b58087/api.hubspot.com/crm/v4/objects/12345/associations/company/67891 \
  -H 'authorization: Bearer {token}' \
  -H 'content-type: application/json' \
  -d '{
    "associationCategory": "USER_DEFINED",
    "associationTypeId": 36
  }'

GET a record from the API:

curl -X GET \
  -H 'authorization: Bearer {token}' \
  https://api.sequin.io/v1/proxy/sync-67b58087/arrakis-prod.salesforce.com/contacts/12345