How to use the DORA API to send deployment activity to Span

Last updated: February 20, 2026

The deployments API allows you to track deployment activity and power critical DORA metrics like deployment frequency, lead time to change, and change failure rate.

Follow the steps below to add a step in your deployment workflow to send this data to Span:

Authentication

Personal Access Token (Beta)

A personal access token may be used. When a personal access token is provided, it assumes the permissions of the person associated with it.

Insufficient Permissions

If the credential provided does not have permission to access the catalog data, the response will include a status of 403 Forbidden. For example, Personal Access Tokens assume the permission levels of the person associated with it, which may not include the permission to access the catalog data.

Invalid Credentials

If the request does not include valid credentials, the response will include a status of 401 Unauthorized .

Additional Request Headers

X-Request-ID

All requests accept the optional header X-Request-ID . If this header is not set, Span will generate a unique request id. In all cases, the response will include the chosen request id in the X-Request-ID header.

Idempotency-Key

Some requests may optionally include the Idempotency-Key header, ensuring requests will only be processed once within a window of 24 hours.

In the case of a collision, the response from the last successful request will be returned as-is with a single additional header X-Replayed-Request: true identifying that the request has been replayed and the response is a cached version of the original.

  • Results will only be saved if the request is successfully executed.

  • Idempotency keys are scoped to the path and method being requested. The same key may be used across different routes or different methods.

  • POST and PATCH request methods accept idempotency keys by default.

  • All other methods (e.g. safe methods such as GET or idempotent methods such as DELETE or PUT) will ignore any idempotency key provided.

Pagination

The catalog api will implement cursor pagination for all list endpoints. A cursor is an opaque string identifying a position in a consistently ordered list of all objects of the same type. In some cases, the cursor may represent the id of a single object, while in others it may be a composite string representing multiple properties of a single object.

When paginating with cursor pagination, you can provide an object’s cursor to either the before or after query parameters. When before is set, you’ll receive the list of objects that are ordered directly before the position of the object represented by the cursor. When after is set, you’ll receive the list of objects that are ordered directly after the position of the object represented by the cursor. In both cases, the limit dictates how many objects to include starting from that position. If both after and before query parameters have been set, the result will be empty.

The following query parameters are supported on list api endpoints:

ParameterDescription

before

A cursor to user in pagination. This defines the end of the page requested. The result will include objects up to limit just before the cursor value.

after

A cursor to user in pagination. This defines the start of the page requested. The result will include objects up to limit just after the cursor value.

limit

The number of results to include. When after is set, this is the number of resources to include with a cursor value greater than after. When before is set, it is the number of resources to include with a cursor value less than before. The default is 10 with a minimum value of 1 and maximum value of 100.

Paginated responses will include the current page details in the meta.page property of the response’s json data. The structure of the page object is as follows:

ParameterDescription

endCursor

An opaque string representing the cursor of last record of the current page. null if there are no more records after the current page. This can be used in the after query param to retrieve the next page.

startCursor

An opaque string representing the cursor the first record of the current page. null if there are no more records before the current page. This can be used in the before query param to retrieve the previous page.

hasNextPage

A boolean indicating whether more results exist following the current result set.

hasPreviousPage

A boolean indicating whether more results exist preceding the current result set.

Deployments

Add Deployment

ParameterRequiredDescription

title

required

Simple descriptive name for this deploy.

description

optional

Expanded description for this deploy.

triggeredAt

required

ISO-8601 UTC timestamp representing the time when the deploy was triggered.

completedAt

optional

ISO-8601 UTC timestamp representing the time when the deploy finished. Defaults to the current time if status is either success or failure.

type

optional

One of deploy, rollback, restart. Defaults to deploy.

status

optional

The state of this deploy. One of success, failure, pending. Defaults to success.

environment

optional

A simple string representing the environment, e.g. production or staging.

version

optional

A simple string representing the version deployed, e.g. a commit sha or semantic version number

httpUrl

optional

A url linking to the external deployment.

services

optional

An array of Span services slug identifiers associated with this deploy.

deployer

optional

An object of deployer details associated with this deploy.

deployer.name

required

The name of the individual who triggered the deploy.

deployer.email

required

The email associated with the individual who triggered the deploy.

git

optional

An object of git details associated with this deploy.

git.repoUrl

required

The url of the git repository associated with this deploy.

git.refName

required

The git ref name associated with this deploy, e.g. a branch name, tag name, or commit sha.

metadata

optional

Any additional data to be included with this deployment. This can be any valid json object.

pullRequests

optional

If using a monorepo or a partial deploy flow, this should be a set of the pull request numbers that are being part of this deployment.

curl -X POST \\
  <https://span.app/api/dora/v1/deployments> \\
  -H "Authorization: Bearer <access token>" \\
  -H "Content-Type: application/json" \\
  -H "Idempotency-Key: <optional idempotency key>" \\
  -d '{
        "title": "Deployment 12345",
        "description": "optional deployment description",
        "triggeredAt": "2024-03-25T18:00:00Z",
        "completedAt": "2024-03-25T18:10:00Z",
        "type": "deploy",
        "status": "success",
        "environment": "production",
        "version": "2fd4e1c",
        "services": ["api", "web"],
        "deployer": {
          "email": "first.last@example.com",
          "name": "First Last"
        },
        "git": {
          "repoUrl": "<https://github.com/example/repository.git>",
          "refName": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
        },
        "pullRequests": [101, 102, 103],
        "metadata": {"anything": "goes"}
      }'

Response (201 Created)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "description": "optional deployment description",
    "triggeredAt": "2024-03-25T18:00:00Z",
    "completedAt": "2024-03-25T18:10:00Z",
    "type": "deploy",
    "status": "success",
    "environment": "production",
    "version": "2fd4e1c",
    "httpUrl": null,
    "services": ["api", "web"],    "deployer": {
      "email": "first.last@example.com",
      "name": "First Last"
    },
    "git": {
      "repoUrl": "<https://github.com/example/repository.git>",
      "refName": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
    },
    "metadata": {"anything": "goes"}
  }
}

Get Deployment

curl <https://span.app/api/dora/v1/deployments/:deploymentId> \\
  -H "Authorization: Bearer <access token>"

Response (200 OK)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "description": "optional deployment description",
    "triggeredAt": "2024-03-25T18:00:00Z",
    "completedAt": "2024-03-25T18:10:00Z",
    "type": "deploy",
    "status": "success",
    "environment": "production",
    "version": "2fd4e1c",
    "httpUrl": null,
    "services": ["api", "web"],
    "deployer": {
      "email": "first.last@example.com",
      "name": "First Last"
    },
    "git": {
      "repoUrl": "<https://github.com/example/repository.git>",
      "refName": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
    },
    "metadata": {"anything": "goes"}
  }
}

List Deployments

curl <https://span.app/api/dora/v1/deployments> \\
  -H "Authorization: Bearer <access token>"

Response (200 OK)

{
  "meta": {
    "page": {
      "endCursor": "...",
      "startCursor": null,
      "hasNextPage": true,
      "hasPreviousPage": false
    },
  },
  "data": [
    {
      "id": "...",
      "description": "optional deployment description",
      "triggeredAt": "2024-03-25T18:00:00Z",
      "completedAt": "2024-03-25T18:10:00Z",
      "type": "deploy",
      "status": "success",
      "environment": "production",
      "version": "2fd4e1c",
      "httpUrl": null,
      "services": ["api", "web"],
      "deployer": {
        "email": "first.last@example.com",
        "name": "First Last"
      },
      "git": {
        "repoUrl": "<https://github.com/example/repository.git>",
        "refName": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
      },
      "metadata": {"anything": "goes"}
    },
    ...
  ]
}

Update Deployment

Deployments may be updated with a PATCH /api/dora/v1/deployments/:deploymentId request. Any parameter containing a null value will unset its value. Parameters not included with the request will remain unchanged.

If status transitions from pending to either success or failure, completedAt will be updated to reflect the time of the request unless it is specified in the update.

ParameterRequiredNullableDescription

title

optional

false

Simple descriptive name for this deploy.

description

optional

true

Expanded description for this deploy.

triggeredAt

required

false

ISO-8601 UTC timestamp representing the time when the deploy was triggered.

completedAt

optional

true

ISO-8601 UTC timestamp representing the time when the deploy finished. Defaults to the current time if status is either success or failure.

type

optional

false

One of deploy, rollback, restart. Defaults to deploy.

status

optional

false

The state of this deploy. One of success, failure, pending. Defaults to success.

environment

optional

true

A simple string representing the environment, e.g. production or staging.

version

optional

true

A simple string representing the version deployed, e.g. a commit sha or semantic version number

httpUrl

optional

true

A url linking to the external deployment.

services

optional

false

An array of Span services slug identifiers associated with this deploy.

deployer

optional

true

An object of deployer details associated with this deploy.

deployer.name

required

false

The name of the individual who triggered the deploy.

deployer.email

required

false

The email associated with the individual who triggered the deploy.

git

optional

true

An object of git details associated with this deploy.

git.repoUrl

required

false

The url of the git repository associated with this deploy.

git.refName

required

false

The git ref name associated with this deploy, e.g. a branch name, tag name, or commit sha.

metadata

optional

false

Any additional data to be included with this deployment. This can be any valid json object. This object will be replaced on updates.

curl -X PATCH \\
  <https://span.app/api/dora/v1/deployments/:deploymentId> \\
  -H "Authorization: Bearer <access token>" \\
  -H "Content-Type: application/json" \\
  -d '{
        "status": "failure"
      }'

Response (200 OK)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "description": "optional deployment description",
    "triggeredAt": "2024-03-25T18:00:00Z",
    "completedAt": "2024-03-25T18:10:00Z",
    "type": "deploy",
    "status": "failure",
    "environment": "production",
    "version": "2fd4e1c",
    "httpUrl": null,
    "services": ["api", "web"],
    "deployer": {
      "email": "first.last@example.com",
      "name": "First Last"
    },
    "git": {
      "repoUrl": "<https://github.com/example/repository.git>",
      "refName": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"
    },
    "metadata": {"anything": "goes"}
  }
}

Delete Deployment

curl -X DELETE \\
  <https://span.app/api/dora/v1/deployments/:deploymentId> \\
  -H "Authorization: Bearer <access token>"

Response (204 No Content)

Ownership

If the services property is defined on the deployment record, ownership will be inferred from the associated services based on their owners definition. For example, let’s assume we have a service api defined as follows:

{
    "id": "...",
    "name": "API Service",
    "slug": "api",
    "description": "api",
    "owners": [
      {
        "type": "team",
        "slug": "team-a"
      }
    ],
    "git": {
      "repoUrl": "<https://github.com/example/repository.git>"
    },
    "metadata": {"anything": "goes"}
  }

If the deployment lists api as one of the associated services, the deployment will be linked to team-a and will be counted in team-a metrics. If no owners are listed for the associated services or if no services were associated with the deployment, then the deployment will remain unlinked but be counted in the organization-level metrics.

Incidents

Add Incident

ParameterRequiredDescription

title

required

Simple descriptive name for this incident.

description

optional

Expanded description for this incident.

severity

optional

The severity of this incident, a number in the range 0-3, with 0 representing the most critical severity level.

issuedAt

required

ISO-8601 UTC timestamp representing the time when the incident was declared.

startedAt

optional

ISO-8601 UTC timestamp representing the time when the work to resolve the incident began.

endedAt

optional

ISO-8601 UTC timestamp representing the time when the incident was successfully resolved.

httpUrl

optional

A url linking to the external incident.

environment

optional

A simple string representing the environment, e.g. production or staging.

services

optional

An array of Span services slug identifiers associated with this incident.

owners

optional

An array of Span owner identifiers.

owners[*].type

required

The type of owner. Only team is supported initially.

owners[*].slug

required

The Span slug of the owning team.

git

optional

An object of git details responsible for this incident.

git.repoUrl

required

The url of the git repository associated with this incident.

git.refName

required

The git ref name responsible for this incident, e.g. a branch name, tag name, or commit sha.

triggeringDeployments

optional

An array of deployment ids that were responsible for the incident.

resolvingDeployments

optional

An array of deployment ids that were responsible for resolving the incident.

metadata

optional

Any additional data to be included with this incident. This can be any valid json object.

curl -X POST \\
  <https://span.app/api/dora/v1/incidents> \\
  -H "Authorization: Bearer <access token>" \\
  -H "Content-Type: application/json" \\
  -H "Idempotency-Key: <optional idempotency key>" \\
  -d '{
        "title": "Incident 12345",
        "severity": 1,
        "issuedAt": "2024-03-25T18:00:00Z",
        "metadata": {"anything": "goes"}
      }'

Response (201 Created)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "title": "Incident 12345",
    "description": null,
    "severity": 1,
    "issuedAt": "2024-03-25T18:00:00Z",
    "startedAt": null,
    "endedAt": null,
    "httpUrl": null,
    "services": [],
    "owners": [],
    "git": null,
    "triggeringDeployments": [],
    "resolvingDeployments": [],
    "metadata": {"anything": "goes"}
  }
}

Get Incident

curl <https://span.app/api/dora/v1/incidents/:incidentId> \\
  -H "Authorization: Bearer <access token>"

Response (200 OK)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "title": "Incident 12345",
    "description": null,
    "severity": 1,
    "issuedAt": "2024-03-25T18:00:00Z",
    "startedAt": null,
    "endedAt": null,
    "httpUrl": null,
    "services": [],
    "owners": [],
    "git": null,
    "triggeringDeployments": [],
    "resolvingDeployments": [],
    "metadata": {"anything": "goes"}
  }
}

List Incidents

curl <https://span.app/api/dora/v1/incidents> \\
  -H "Authorization: Bearer <access token>"

Response (200 OK)

{
  "meta": {
    "page": {
      "endCursor": "...",
      "startCursor": null,
      "hasNextPage": true,
      "hasPreviousPage": false
    }
  },
  "data": [
    {
      "id": "...",
      "title": "Incident 12345",
      "description": null,
      "severity": 1,
      "issuedAt": "2024-03-25T18:00:00Z",
      "startedAt": null,
      "endedAt": null,
      "httpUrl": null,
      "services": [],
      "owners": [],
      "git": null,
      "triggeringDeployments": [],
      "resolvingDeployments": [],
      "metadata": {"anything": "goes"}
    },
    ...
  ]
}

Update Incident

Incidents may be updated with a PATCH /api/dora/v1/incidents/:incidentId request. Any parameter containing a null value will unset its value. Parameters not included with the request will remain unchanged.

ParameterRequiredNullableDescription

title

optional

false

Simple descriptive name for this incident.

description

optional

true

Expanded description for this incident.

severity

optional

true

The severity of this incident, a number in the range 0-3, with 0 representing the most critical severity level.

issuedAt

optional

false

ISO-8601 UTC timestamp representing the time when the incident was declared.

startedAt

optional

true

ISO-8601 UTC timestamp representing the time when the work to resolve the incident began.

endedAt

optional

true

ISO-8601 UTC timestamp representing the time when the incident was successfully resolved.

httpUrl

optional

true

A url linking to the external incident.

environment

optional

true

A simple string representing the environment, e.g. production or staging.

services

optional

false

An array of Span services slug identifiers associated with this incident.

owners

optional

false

An array of Span owner identifiers.

owners[*].type

required

false

The type of owner. Only team is supported initially.

owners[*].slug

required

false

The Span slug of the owning team.

git

optional

true

An object of git details responsible for this incident.

git.repoUrl

required

false

The url of the git repository associated with this incident.

git.refName

required

false

The git ref name responsible for this incident, e.g. a branch name, tag name, or commit sha.

triggeringDeployments

optional

false

An array of deployment ids that were responsible for the incident.

resolvingDeployments

optional

false

An array of deployment ids that were responsible for resolving the incident.

metadata

optional

false

Any additional data to be included with this incident. This can be any valid json object.

curl -X PATCH \\
  <https://span.app/api/dora/v1/incidents/:incidentId> \\
  -H "Authorization: Bearer <access token>" \\
  -H "Content-Type: application/json" \\
  -d '{
        "startedAt": "2024-03-25T19:00:00Z"
      }'

Response (200 OK)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "title": "Incident 12345",
    "description": null,
    "severity": 1,
    "issuedAt": "2024-03-25T18:00:00Z",
    "startedAt": "2024-03-25T19:00:00Z",
    "endedAt": null,
    "httpUrl": null,
    "services": [],
    "owners": [],
    "git": null,
    "triggeringDeployments": [],
    "resolvingDeployments": [],
    "metadata": {"anything": "goes"}
  }
}

Delete Incident

curl -X DELETE \\
  <https://span.app/api/dora/v1/incidents/:incidentId> \\
  -H "Authorization: Bearer <access token>"

Response (204 No Content)

Ownership

If the owners property is set, the incident will be counted in metrics for all teams explicitly listed. Otherwise, the incident will be counted in metrics at the organization-level and remain unlinked from any specific team.

Services

Add Service

ParameterRequiredDescription

name

required

Simple descriptive name for this service.

slug

optional

A unique slug representing this service. If one isn’t provided, it will be generated from the name. Must match the following pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ if provided.

description

optional

Expanded description for this service.

owners

optional

An array of Span owner identifiers.

owners[*].type

required

The type of owner. Only team is supported initially.

owners[*].slug

required

The Span slug of the owning team.

git

optional

An object of git details associated with this service.

git.repoUrl

required

The url of the git repository associated with this service.

metadata

optional

Any additional data to be included with this service. This can be any valid json object.

curl -X POST \\
  <https://span.app/api/dora/v1/services> \\
  -H "Authorization: Bearer <access token>" \\
  -H "Content-Type: application/json" \\
  -H "Idempotency-Key: <optional idempotency key>" \\
  -d '{
        "name": "Service A",
        "slug": "service-a",
        "description": "optional service description",
        "owners": [
          {
            "type": "team",
            "slug": "team-a"
          }
        ],
        "git": {
          "repoUrl": "<https://github.com/example/repository.git>"
        },
        "metadata": {"anything": "goes"}
      }'

Response (201 Created)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "slug": "service-a",
    "title": "Service A",
    "description": "optional service description",
    "owners": [
      {
        "type": "team",
        "slug": "team-a"
      }
    ],
    "git": {
      "repoUrl": "<https://github.com/example/repository.git>"
    },
    "metadata": {"anything": "goes"}
  }
}

Get Service

curl <https://span.app/api/dora/v1/services/:serviceId> \\
  -H "Authorization: Bearer <access token>"

Response (200 OK)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "name": "Service A",
    "slug": "service-a",
    "description": "optional service description",
    "owners": [
      {
        "type": "team",
        "slug": "team-a"
      }
    ],
    "git": {
      "repoUrl": "<https://github.com/example/repository.git>"
    },
    "metadata": {"anything": "goes"}
  }
}

List Services

curl <https://span.app/api/dora/v1/services> \\
  -H "Authorization: Bearer <access token>"

Response (200 OK)

{
  "meta": {
    "page": {
      "endCursor": "...",
      "startCursor": null,
      "hasNextPage": true,
      "hasPreviousPage": false
    },
  },
  "data": [
    {
      "id": "...",
      "name": "Service A",
      "slug": "service-a",
      "description": "optional service description",
      "owners": [
        {
          "type": "team",
          "slug": "team-a"
        }
      ],
      "git": {
        "repoUrl": "<https://github.com/example/repository.git>"
      },
      "metadata": {"anything": "goes"}
    },
    ...
  ]
}

Update Service

Services may be updated with a PATCH /api/dora/v1/services/:serviceId request. Any parameter containing a null value will unset its value. Parameters not included with the request will remain unchanged.

ParameterRequiredNullableDescription

name

optional

false

Simple descriptive name for this service.

slug

optional

false

A unique slug representing this service. If one isn’t provided, it will be generated from the name. Must match the following pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ if provided.

description

optional

true

Expanded description for this service.

owners

optional

false

An array of Span owner identifiers.

owners[*].type

required

false

The type of owner. Only team is supported initially.

owners[*].slug

required

false

The Span slug of the owning team.

git

optional

true

An object of git details associated with this service.

git.repoUrl

required

false

The url of the git repository associated with this service.

metadata

optional

false

Any additional data to be included with this service. This can be any valid json object. This object will be replaced on updates.

curl -X PATCH \\
  <https://span.app/api/dora/v1/services/:serviceId> \\
  -H "Authorization: Bearer <access token>" \\
  -H "Content-Type: application/json" \\
  -d '{
        "description": "api documentation"
      }'

Response (200 OK)

{
  "meta": {
    "cursor": "..."
  },
  "data": {
    "id": "...",
    "name": "Service A",
    "slug": "service-a",
    "description": "api documentation",
    "owners": [
      {
        "type": "team",
        "slug": "team-a"
      }
    ],
    "git": {
      "repoUrl": "<https://github.com/example/repository.git>"
    },
    "metadata": {"anything": "goes"}
  }
}

Delete Service

curl -X DELETE \\
  <https://span.app/api/dora/v1/services/:serviceId> \\
  -H "Authorization: Bearer <access token>"

Response (204 No Content)

Ownership: Connecting deployments to teams

Ownership determines which team's DORA metrics a deployment contributes to. There are three options:

Option 1: Services array (recommended)

> "services": ["payments-api", "checkout-worker"]
>

Span resolves ownership via the service's team owner. If a slug doesn't exist, Span auto-creates the service — but without a team owner. A Span admin must set ownership via Catalog → Services → [service] → Owner. Until this is done, deployments fall back to root org attribution.

Support tip: "Deployments visible in catalog but not under my team" almost always means missing service-to-team ownership.

Option 2: Explicit PR linking
Provide the pullRequests array (PR numbers) alongside git.repoUrl. Ownership is then inferred from the PRs' authors and their team membership.

Option 3: Automatic PR linking (on request)
Span can automatically link deployments to PRs using the git.refName commit SHA — no pullRequests array required. This must be enabled by Span support on a per-org basis.

FAQ:

When Will my deployment appear in Span?

Deployments are stored immediately after a successful API call. Enrichment (PR links, lead time) happens asynchronously — expect full visibility in DORA metric pages within approximately 3 hours. The deployment will appear in the catalog right away, but metric pages have additional requirements (see below).

What are the requirements for metrics to show data?

Status must be success
Only "status": "success" deployments count. pending and failure are excluded from all metric calculations.

Environment must be production
Only environments whose name is null (omitted) or contains prod or prd (case-insensitive) are counted:
- "production", "prod", "PRD-us-east-1", omitted
- "staging", "dev", "test", "qa", "pre-prod"

Note: "pre-prod" does not match — the string must contain prod or prd.