Connect
1 operation under /v1/connect/start (POST): parameters, status codes, refusal bodies, and the same request in curl, HTTP, Python and TypeScript.
Base URL: https://api.codespar.dev
Every operation below requires a Bearer token. See Authentication.
POST /v1/connect/start
https://api.codespar.dev/v1/connect/startBegin 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
| Field | Type | Required | Description |
|---|---|---|---|
redirect_uri | string (uri) | yes | — |
scopes | string | no | — |
server_id | string | yes | — |
user_id | string | yes | — |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
400 | object | The body did not match the schema. |
404 | object | The provider has no OAuth configuration in the catalog. |
422 | object | The 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. |
500 | object | The platform's OAuth client credential is not seeded for this provider. A configuration defect on our side. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
authorize_url | string (uri) | yes | Send the user here. Carries the client id, our callback as its redirect_uri, the state token, response_type=code and the resolved scopes. |
expires_at | string (date-time) | yes | Ten minutes after the call. A callback arriving later is refused. |
link_token | string | yes | Single-use state token, also embedded in authorize_url. |
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);
}{
"link_token": "string",
"authorize_url": "https://example.com/hook",
"expires_at": "2026-01-15T12:00:00.000Z"
}Connections
11 operations under /v1/connections (GET POST DELETE PATCH PUT): parameters, status codes, refusal bodies, and the same request in curl, HTTP, Python and TypeScript.
MCP Servers
8 operations under /v1/mcp-servers (GET POST PATCH DELETE): parameters, status codes, refusal bodies, and the same request in curl, HTTP, Python and TypeScript.