Skip to content

Finish a connect

View as Markdown
POST
/v1/connections/finish
curl --request POST \
--url https://example.com/v1/connections/finish \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "state": "example", "code": "example", "installationId": "example", "setupAction": "example", "error": "example", "errorDescription": "example" }'

Takes what the app sent back to the callback page (state and code, with installationId and setupAction from a GitHub App; or error). Only whoever started the request may finish it. Exchanges the code, learns the account, compares what was granted with what was asked and stores the connection; a run that waits goes on. A company connect that doesn’t name reconnects lands on the company’s connection of the account signed in to, when there is one, so one account never has two. reconnected says whether it landed on a connection that was already there, which keeps its name. A new connection whose name another connection took meanwhile is named the first free <name> 2, <name> 3 and so on, and labelTaken gives the name it was to get. A person who declined, or who granted less than asked, gets kind: 'declined' and the request’s missing permissions. A GitHub App’s attaches an installation only if the person’s GitHub account reaches it: the one GitHub sent back, the one they picked at the start, or the only one they reach. When they reach several and picked none, it answers kind: 'pick-installation': the request stays pending with its installations to pick from (start it again with installationId, or newInstallation).

Idempotency-Key
string
>= 1 characters

Caller-supplied idempotency key, scoped to the caller: the same key from someone else in the workspace is their own request (from 0.1.5). Retries with the same key return the original response byte-identical (per docs/API-ROUTE-CONVENTIONS.md §3.1). A retry sent while the first request still runs is answered 409 idempotency-key-in-flight with Retry-After, on a runtime whose store holds keys (from 0.1.5); retry after it, and you get the first request’s answer. An answer that carries a secret (a new API key or public run token, a session token, a generated signing secret) isn’t kept: a retry gets 409 idempotency-key-replay-withheld, with the first request’s status and when it succeeded (from 0.1.5). A request whose key store can’t be read before it runs is answered 503 idempotency-store-unavailable with Retry-After: nothing ran, so retry with the same key (from 0.3.0).

Media typeapplication/json

What the app sent back to the callback page, each as a string. Only whoever started the request may finish it.

object
state
required

The one the app sent back.

string
>= 1 characters <= 2048 characters
code
string
>= 1 characters <= 2048 characters
installationId
string
>= 1 characters <= 2048 characters
setupAction
string
>= 1 characters <= 2048 characters
error
string
>= 1 characters <= 2048 characters
errorDescription
string
>= 1 characters <= 2048 characters
Examplegenerated
{
"state": "example",
"code": "example",
"installationId": "example",
"setupAction": "example",
"error": "example",
"errorDescription": "example"
}

The outcome.

Media typeapplication/json
object
kind
required

declined: the person declined, or granted less than asked (request.missing). pick-installation: a GitHub App’s person reaches several installations and picked none; the request stays pending with its installations.

string
Allowed values: connected declined pick-installation
request
required

A connect: the owner goes to connectUrl, consents at the app, and comes back. A run that needs a connection it lacks waits on one.

object
requestId
required
string format: uuid
envName
required
string
appId
required
string format: uuid
app
required

The app’s entry id.

string
owner
required

Who owns a connection: one member (kind: member, with their userId), or the company (kind: company, the workspace’s own account).

object
kind
required
string
Allowed values: member company
userId

The member. Present when kind is member.

string
permissions
required

The permissions asked for: the ones needed, and the ones already granted.

Array<string>
says
required

What each asks for, in plain words.

Array<string>
reconnects

The connection it connects again; the same account is required.

string format: uuid
label

The name asked for the connection it makes. A reconnect keeps the connection’s.

string
runId

The run that waits for it.

string
name

The tool’s name for the connection, when a run waits.

string
startedBy

Who started it last: <kind>:<id>. Only they may finish it.

string
state
required
string
Allowed values: pending connected declined expired failed
failure

Why it failed: account-mismatch, app-refused, store-write-failed.

string
missing

The permissions the app granted less than asked.

Array<string>
installations

A GitHub App’s, while it’s pending: the app’s installations the person’s GitHub account reaches, when the finish found several and none was picked. They pick one and start again with installationId, or install the app on another account with newInstallation.

Array<object>

A GitHub App installation the person can reach.

object
installationId
required
string
account
required

The account it’s on: its login, or the enterprise’s slug.

object
id
required

The account’s stable id at the app.

string
label
required

What people see: an email address, a login.

string
connectionId

The connection it made.

string format: uuid
connectUrl
required

Where the owner starts.

string format: uri
expiresAt
required
string format: date-time
createdAt
required
string format: date-time
createdBy
required
string
connection

Present when kind is connected.

object
connectionId
required
string format: uuid
envName
required
string
appId
required

The registration it goes through.

string format: uuid
app
required

The app’s entry id.

string
owner
required

Who owns a connection: one member (kind: member, with their userId), or the company (kind: company, the workspace’s own account).

object
kind
required
string
Allowed values: member company
userId

The member. Present when kind is member.

string
account
required

Whose account a connection is at the app.

object
id
required

The account’s stable id at the app.

string
label
required

What people see: an email address, a login.

string
label

The name people know it by: the one asked for at the connect, else the account’s label. Absent on a connection made before connections had names; show account.label then.

string
main

Only ever true: the person’s main connection through its registration in its env, the one their agents use when no choice names another. A person’s first connection has none; their second connection makes the first their main. The company’s has none.

boolean
permissions
required

The entry’s permission keys the app granted.

Array<string>
state
required

working: runs can use it. needs-reconnecting: the app no longer accepts it; connect again. removing: a disconnect is under way. removed: gone.

string
Allowed values: working needs-reconnecting removing removed
stateReason

Why it’s in its state: invalid-grant (the app withdrew the grant), no-refresh-token (the app gave no way to renew it), token-missing (its stored token is gone), store-write-failed (its token couldn’t be stored at the connect), installation-missing (the GitHub App was uninstalled from the account), installation-permissions (an owner took permissions from the installation), suspended (the installation was suspended), sessions-revoked (Google revoked the person’s sessions), access-expired (the app gave no refresh token, and its access token ends within a minute, or has ended). Other values may be added; state says what to do.

string
installationId

A GitHub App’s installation.

string
accessEndsAt

When its access token ends, for a connection the app gave no refresh token. From one minute before then, it needs reconnecting (access-expired), and reads say so too. Absent for one that renews.

string format: date-time
connectedAt
required

When its current grant was stored: the connect, or the last reconnect.

string format: date-time
lastUsedAt

When a run last used it, to the hour.

string format: date-time
createdAt
required
string format: date-time
createdBy
required
string
updatedAt
required
string format: date-time
removedAt
string format: date-time
removedBy
string
removedReason
string
Allowed values: disconnected revoked-at-app uninstalled registration-removed replaced
withdrawn

What a removal did at the app. at-app: access was withdrawn there. app-failed: the app refused the revoke; the token is gone here all the same. kept-for-other-connection: another live connection uses the same grant. not-supported: the app has no revoke that would touch only this connection.

string
Allowed values: at-app app-failed kept-for-other-connection not-supported
reconnected

Present when kind is connected. true: the finish landed on a connection that was already there, the one reconnects named or the owner’s connection of the same account, the company’s or the person’s, and that connection keeps its name. false: it made a new one.

boolean
labelTaken

Present when kind is connected and the name the new connection was to get (the one asked for, else the account’s label after the name rules) was already another connection’s by the finish. The connection is then named the first free <name> 2, <name> 3 and so on, which connection.label holds.

string
reviewerSeat

On a server with approvals, for a member who connected: whether they have a reviewer seat, which approving a send from their own account needs.

boolean
main

Present when kind is connected, reconnected is false, and the person already had a connection through the registration in the env.

object
state
required
string
Allowed values: set kept missing
connectionId

With set and kept.

string format: uuid
Example
{
"kind": "connected",
"request": {
"owner": {
"kind": "member"
},
"state": "pending"
},
"connection": {
"owner": {
"kind": "member"
},
"state": "working",
"removedReason": "disconnected",
"withdrawn": "at-app"
},
"main": {
"state": "set"
}
}

Malformed body, unknown field or no state; or neither code nor error (bad-input, details.field).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Missing / malformed / expired / revoked bearer token.

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Someone other than whoever started the request (connection-not-yours); or a GitHub App’s person whose GitHub account doesn’t reach the installation, or any (connection-installation-unreachable, with details.connectRequestId: start that request again with newInstallation to install the app on their account).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

No request for that state (connection-request-not-found).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Idempotency-Key was reused with a different body; the request was finished already (connection-request-used); a reconnect signed in to another account (connection-account-mismatch); or the connection is still being disconnected: disconnect it again to finish, then connect (connection-removing).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The request expired (connection-request-expired), or the sign-in took longer than its state lives: start again (connection-state-expired).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The request body is over the API’s limit (request-too-large; details.maxBytes says how much).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

Server error (unmapped domain code or framework crash).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The app wouldn’t give a token for the code: its client id, secret or redirect URL (connection-app-refused).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

The connection couldn’t be stored just now (connection-store-failed), or the Idempotency-Key store couldn’t be read before the request ran (idempotency-store-unavailable, with Retry-After).

Media typeapplication/json
object
error
required
object
code
required

Stable machine-readable discriminant. Values match domain error codes (see docs/API-ROUTE-CONVENTIONS.md §4.3).

string
message
required
string
details

Optional, kind-specific.

object
key
additional properties
any
requestId
required

Server-assigned request id; also echoed via X-Request-Id header.

string
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {},
"requestId": "example"
}
}

See also