Skip to main content

Connect

1 operation under /v1/connect/start (POST): parameters, status codes, refusal bodies, and the same request in curl, HTTP, Python and TypeScript.

2 min read
View MarkdownEdit on GitHub

Base URL: https://api.codespar.dev

Every operation below requires a Bearer token. See Authentication.

POST /v1/connect/start

POSThttps://api.codespar.dev/v1/connect/start
Deprecated

Begin the Connect Link OAuth flow for a provider

DEPRECATED alias of POST /v1/connections/start, kept for two releases. The same handler is registered at both paths and both require the same grant, so switching the path changes nothing else. Build against the canonical path, which carries the full description of this flow.

TWO DIFFERENT REDIRECT URIS ARE IN PLAY, and mixing them up is the usual first failure. The redirect_uri in the body is where OUR callback sends the browser once the flow finishes, and it is stored against the state token; it must be https. The redirect_uri embedded inside the returned authorize_url is our own callback, and that is the value the provider has to have allowlisted.

link_token is the same value as the state parameter inside authorize_url. It is single use and expires at expires_at, ten minutes out.

The refusals are bare { error, ... } bodies, not the nested envelope the rest of this document mostly uses. A provider with no OAuth configuration is 404. A missing platform client credential is 500 — that is our seeding defect, not a caller error, and no change to the request fixes it.

Request body

FieldTypeRequiredDescription
redirect_uristring (uri)yes—
scopesstringno—
server_idstringyes—
user_idstringyes—

Responses

StatusBodyDescription
200objectOK
400objectThe body did not match the schema.
404objectThe provider has no OAuth configuration in the catalog.
422objectThe project is in environment="test" and this provider has no test venue, so the flow is refused BEFORE a state token is minted — a refused start leaves no half-begun link behind. Sending a test project to the provider's LIVE consent screen would have it authorise a real account and vault a real token under a project that is not supposed to hold one (ent#722). Not retryable; the same call from a live project succeeds.
500objectThe platform's OAuth client credential is not seeded for this provider. A configuration defect on our side.

Response 200

FieldTypeRequiredDescription
authorize_urlstring (uri)yesSend the user here. Carries the client id, our callback as its redirect_uri, the state token, response_type=code and the resolved scopes.
expires_atstring (date-time)yesTen minutes after the call. A callback arriving later is refused.
link_tokenstringyesSingle-use state token, also embedded in authorize_url.
Example request
curl -X POST https://api.codespar.dev/v1/connect/start \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "server_id": "srv_0000000000000000",
       "user_id": "user_0000000000000000",
       "redirect_uri": "https://example.com/hook",
       "scopes": "string"
     }'
POST /v1/connect/start HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json

{
  "server_id": "srv_0000000000000000",
  "user_id": "user_0000000000000000",
  "redirect_uri": "https://example.com/hook",
  "scopes": "string"
}
import os
import requests

res = requests.post(
    "https://api.codespar.dev/v1/connect/start",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
    json={
      "server_id": "srv_0000000000000000",
      "user_id": "user_0000000000000000",
      "redirect_uri": "https://example.com/hook",
      "scopes": "string"
    },
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/connect/start", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "server_id": "srv_0000000000000000",
    "user_id": "user_0000000000000000",
    "redirect_uri": "https://example.com/hook",
    "scopes": "string"
  }),
});

const data = await res.json();
const auth = await session.authorize(serverId, { redirectUri, scopes });

// The same operation on the generated REST client (cs.api, from 0.12.0):
const r = await cs.api.response("post", "/v1/connect/start", {
  body: {
    server_id: "srv_0000000000000000",
    user_id: "user_0000000000000000",
    redirect_uri: "https://example.com/hook",
    scopes: "string"
  }
});
// r.status is one of the documented statuses (200, 422),
// each with its own body shape in r.data; nothing here throws on 422.
if (r.ok) {
  console.log(r.data);
}
Example response 200
application/json
{
  "link_token": "string",
  "authorize_url": "https://example.com/hook",
  "expires_at": "2026-01-15T12:00:00.000Z"
}
Connect | CodeSpar