Connections
Generated HTTP reference for the 10 operations the published OpenAPI document describes under connections.
Connections
This page is generated from the published OpenAPI document. It is complete with respect to that document and says nothing about surfaces the document does not describe yet. See what is generated here for what that means.
Base URL: https://api.codespar.dev
Every operation below requires a Bearer token. See Authentication.
A connection stores a provider credential (encrypted in the vault) plus its merchant config, scoped to your account and project. Connections are org-scoped resources under /v1/connections; sessions read them, they don't own them. The one session-scoped surface is the read-only list of what a given session can currently reach.
Base URL: https://api.codespar.dev
All endpoints require authentication via Bearer token. See Authentication.
POST /v1/connections
Creates a connection (or rotates the credential of an existing one for the same server_id/user_id). The secret is encrypted into the vault; it is never returned by any read endpoint.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
server_id | string | Yes | Provider identifier from the servers catalog |
secret | string | object | Yes | The credential. A string for single-secret providers; an object of named secrets for path-secret providers (each key must match the provider's declared secret names; extra or missing keys are rejected) |
display_name | string | No | Operator-facing label, max 128 chars |
user_id | string | No | End-user binding for per-user connections |
connection_metadata | object | No | Provider-specific merchant config the agent shouldn't have to know (fiscal company id, split wallet id, default customer id). Max 64 keys / 32 KB serialized. Merged into upstream calls at execute time |
Response -- 201 Created (or 200 OK on rotation)
{
"id": "conn_abc123",
"user_id": null,
"server_id": "asaas",
"auth_type": "api_key",
"status": "connected",
"display_name": "Asaas production",
"metadata": {},
"connection_metadata": { "default_customer_id": "cus_000042" },
"cert_metadata": {},
"created_at": "2026-07-01T12:00:00Z",
"connected_at": "2026-07-01T12:00:00Z",
"revoked_at": null,
"expires_at": null
}metadata is OAuth-derived provider metadata (set by callback flows); connection_metadata is your operator-supplied merchant config; cert_metadata is parsed X.509 info for cert-auth connections.
GET /v1/connections
Lists the project's connections, newest first.
Query parameters
| Parameter | Type | Description |
|---|---|---|
limit | int | Page size |
user_id | string | Filter by end-user binding |
server_id | string | Filter by provider |
status | string | pending | connected | revoked | expired |
Response -- 200 OK
{
"connections": [ { "id": "conn_abc123", "server_id": "asaas", "status": "connected", "...": "..." } ]
}GET /v1/connections/:id
Returns one connection (same shape as create). 404 not_found for unknown or cross-tenant ids. The secret is never included.
POST /v1/connections/:id/revoke
Marks the connection revoked AND purges the backing vault rows atomically — after revoke, the credential is gone at both the status gate and the vault lookup. The row itself remains for audit.
Response -- 200 OK
{ "id": "conn_abc123", "status": "revoked" }Revoking an already-revoked connection returns { "id": "...", "status": "revoked", "already": true }.
PATCH /v1/connections/:id/metadata
Updates connection_metadata (merchant config) without touching the credential. Same 64-key / 32 KB cap as create.
PUT /v1/connections/:id/webhook-secret
Sets or rotates the provider webhook signing secret bound to this connection (used to verify inbound POST /v1/webhooks/:server_id/:connection_id deliveries).
DELETE /v1/connections/:id
Hard-deletes the connection row (vault rows included). Prefer revoke in production — it preserves the audit trail.
Credential validation helpers also live here: POST /v1/connections/hmac-validate and POST /v1/connections/jwt-validate round-trip a candidate credential against the provider before you store it.
GET /v1/sessions/:id/connections
The session-scoped, read-only view: which providers this session can currently reach, with status and tool counts.
Auth required: Yes
curl example
curl https://api.codespar.dev/v1/sessions/ses_abc123/connections \
-H "Authorization: Bearer csk_live_abc123..."Response -- 200 OK
{
"data": [
{
"id": "stripe",
"name": "Stripe",
"category": "payments",
"country": "GLOBAL",
"auth_type": "api_key",
"connected": true,
"tools_count": 8,
"status": "ready"
},
{
"id": "mercadopago",
"name": "Mercado Pago",
"category": "payments",
"country": "BR",
"auth_type": "oauth",
"connected": true,
"tools_count": 6,
"status": "ready"
}
],
"total": 2,
"session_id": "ses_abc123"
}End-user OAuth (a customer connecting their own Mercado Pago / Shopify) runs through Connect Links (POST /v1/connect/start plus a hosted callback), not through a session endpoint. See Connect Links.
Error codes
| Code | HTTP | Description |
|---|---|---|
invalid_body / invalid_query | 400 | Request didn't match the schema |
not_found | 404 | Connection unknown or cross-tenant |
keys_mismatch | 400 | Path-secret object keys don't match the provider's declared names |
Next steps
Every operation, from the spec
Generated from the published OpenAPI document, so it never drifts from what the API actually serves. The section above is written by hand and carries what a schema cannot: the object model, field rules, and the order to call things in.
GET /v1/connections
List the connections in this project
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer | no | — |
server_id | string | no | — |
status | "pending" | "connected" | "revoked" | "expired" | no | — |
user_id | string | no | — |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
400 | object | Bad Request — the body or query did not match the schema. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
connections | array of object | yes | — |
Example response
{
"connections": [
{
"id": "obj_0000000000000000",
"user_id": "user_0000000000000000",
"server_id": "srv_0000000000000000",
"auth_type": "string",
"status": "pending",
"connection_metadata": {},
"cert_metadata": {},
"created_at": "2026-01-15T12:00:00.000Z"
}
]
}Example request
curl -X GET https://api.codespar.dev/v1/connections \
-H "Authorization: Bearer $CODESPAR_API_KEY"POST /v1/connections
Register a provider key, or rotate the one already there
Request body
| Field | Type | Required | Description |
|---|---|---|---|
connection_metadata | object | no | — |
display_name | string | no | — |
secret | string | object | yes | — |
server_id | string | yes | — |
user_id | string | no | — |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
201 | object | OK |
400 | object | The body did not parse, the owner could not be resolved, the server is not key-authenticated, or the secret's shape or keys do not match what the provider declares. |
403 | object | Service auth without x-codespar-user, or with a role below admin. |
404 | object | No such server in the catalog. |
500 | object | The provider's catalog row declares no path-secret refs, so there is nowhere to put the values. A seeding defect, not a bad request. |
503 | object | The vault or the connection write failed. Nothing was persisted. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
auth_type | string | yes | Mirrors the catalog's auth_type at connect time: api_key, path_secret, cert, hmac_signed, jwt_ecdsa, two_header, oauth, cdp or none. Left open because the column is plain text. |
cert_metadata | object | yes | Issuer, subject, validity window and SHA-256 fingerprint parsed from the uploaded PEM at connect time. \{\} for every non-cert connection. |
connected_at | string,null (date-time) | yes | — |
connection_metadata | object | yes | Operator-supplied merchant config the router merges into upstream calls. \{\} when nothing was set. |
created_at | string (date-time) | yes | — |
display_name | string,null | yes | — |
expires_at | string,null (date-time) | yes | — |
id | string | yes | ca_-prefixed. Globally unique, visible only inside the owning org and project. |
metadata | object,null | yes | Provider metadata the OAuth callback wrote (scope, refresh ref) or the provisioning projection wrote (account_id). Always present; null for a key registered through POST /v1/connections, which never sets it. |
revoked_at | string,null (date-time) | yes | — |
server_id | string | yes | Catalog id of the provider this connection authenticates. |
status | "pending" | "connected" | "revoked" | "expired" | yes | — |
user_id | string | yes | — |
Example response
{
"id": "obj_0000000000000000",
"user_id": "user_0000000000000000",
"server_id": "srv_0000000000000000",
"auth_type": "string",
"status": "pending",
"connection_metadata": {},
"cert_metadata": {},
"created_at": "2026-01-15T12:00:00.000Z"
}Example request
curl -X POST https://api.codespar.dev/v1/connections \
-H "Authorization: Bearer $CODESPAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"server_id": "srv_0000000000000000",
"secret": "string",
"display_name": "Example",
"user_id": "user_0000000000000000",
"connection_metadata": {}
}'GET /v1/connections/engine/{run_id}/status
Poll a browser-driven signup run
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
run_id | string | yes | — |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
404 | object | No run with that id inside the caller's org and project. |
410 | object | The paused run expired before it was resumed. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
code | "flow_failed" | "capacity" | "no_credential_captured" | "probe_failed" | "drive_deadline_exceeded" | "provider_account_not_registered" | "drive_stalled" | "resume_inputs_unavailable" | no | Why the run failed. A stored value outside this vocabulary is reported as absent rather than passed through, so a failed run can render as its status alone. |
connection_id | string | no | The ca_ id of the connection the run produced. Present once the run reaches provisioned. |
failed_step_id | string | no | — |
probe_result | — | no | Result of the post-provision reachability probe, when one ran. |
prompt | string | no | Present while the run waits on the customer. Fallback copy when the modal has none of its own. |
status | "running" | "needs_verification" | "provisioned" | "failed" | yes | — |
verification | object | no | Resolved from the provider's public descriptor. Present only while status is needs_verification. |
Example response
{
"status": "running",
"prompt": "string",
"verification": {
"mechanism": "code",
"resend": true
},
"connection_id": "conn_0000000000000000",
"code": "flow_failed",
"failed_step_id": "failedstep_0000000000000000"
}Example request
curl -X GET https://api.codespar.dev/v1/connections/engine/{run_id}/status \
-H "Authorization: Bearer $CODESPAR_API_KEY"POST /v1/connections/start
Begin the Connect Link OAuth flow for a provider
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 | Bad Request — the body or query did not match the schema. |
404 | object | The provider has no OAuth configuration in the catalog. |
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 client_id, our callback as 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. |
Example response
{
"link_token": "string",
"authorize_url": "https://example.com/hook",
"expires_at": "2026-01-15T12:00:00.000Z"
}Example request
curl -X POST https://api.codespar.dev/v1/connections/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/connections/subaccount/{id}/revoke
Revoke a provisioned subaccount and try to delete it upstream
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | A ca_ connection id, or a pr_ provisioning record id on the operator-internal path. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
403 | object | This is a write, so it carries a role floor: a service-auth caller must send x-codespar-user and hold admin or above. |
404 | object | No connection or operator-internal record with that id is reachable by this caller. |
500 | object | The revoke threw unexpectedly. |
503 | object | The internal phase failed and left nothing changed. Retry. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
already | true | no | Present when the subaccount was already revoked. Nothing changed. |
connection_id | string | yes | The connection projection's id, or the provisioning record's id when there is no projection. |
record_id | string | yes | — |
status | "revoked" | yes | — |
upstream | "deleted" | "delete_failed" | "not_applicable" | "orphaned" | yes | What happened at the provider. delete_failed and orphaned mean an account may still exist there; the local credential is gone either way. |
Example response
{
"status": "revoked",
"record_id": "record_0000000000000000",
"connection_id": "conn_0000000000000000",
"upstream": "deleted",
"already": true
}Example request
curl -X POST https://api.codespar.dev/v1/connections/subaccount/{id}/revoke \
-H "Authorization: Bearer $CODESPAR_API_KEY"GET /v1/connections/subaccount/{id}/status
Read whether a provisioned subaccount can transact yet
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | A ca_ connection id, or a pr_ provisioning record id on the operator-internal path. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
404 | object | No connection or operator-internal record with that id is reachable by this caller. |
500 | object | The status read threw unexpectedly. |
502 | object | The provider read did not produce a status. Usually the live call failed or timed out, and a retry is the right response. TWO OF THE CASES BEHIND THIS CODE ARE NOT TRANSIENT and retrying never clears them: the provider has no subaccount descriptor in this deployment, and no platform account credential is registered for it. Both are configuration defects on our side; error.message distinguishes them from a provider outage. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
account_ref | string | yes | The upstream account identifier. Empty string when the record never reached one. |
capabilities | object | no | Per-capability activation states as the provider reports them, for example card_payments: "active". |
charges_enabled | boolean | yes | — |
status | "provisioned" | "revoked" | yes | — |
Example response
{
"status": "provisioned",
"charges_enabled": true,
"capabilities": {},
"account_ref": "string"
}Example request
curl -X GET https://api.codespar.dev/v1/connections/subaccount/{id}/status \
-H "Authorization: Bearer $CODESPAR_API_KEY"GET /v1/connections/{id}
Read one connection
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | ca_-prefixed connection id |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
404 | object | Not Found |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
auth_type | string | yes | Mirrors the catalog's auth_type at connect time: api_key, path_secret, cert, hmac_signed, jwt_ecdsa, two_header, oauth, cdp or none. Left open because the column is plain text. |
cert_metadata | object | yes | Issuer, subject, validity window and SHA-256 fingerprint parsed from the uploaded PEM at connect time. \{\} for every non-cert connection. |
connected_at | string,null (date-time) | yes | — |
connection_metadata | object | yes | Operator-supplied merchant config the router merges into upstream calls. \{\} when nothing was set. |
created_at | string (date-time) | yes | — |
display_name | string,null | yes | — |
expires_at | string,null (date-time) | yes | — |
id | string | yes | ca_-prefixed. Globally unique, visible only inside the owning org and project. |
metadata | object,null | yes | Provider metadata the OAuth callback wrote (scope, refresh ref) or the provisioning projection wrote (account_id). Always present; null for a key registered through POST /v1/connections, which never sets it. |
revoked_at | string,null (date-time) | yes | — |
server_id | string | yes | Catalog id of the provider this connection authenticates. |
status | "pending" | "connected" | "revoked" | "expired" | yes | — |
user_id | string | yes | — |
Example response
{
"id": "obj_0000000000000000",
"user_id": "user_0000000000000000",
"server_id": "srv_0000000000000000",
"auth_type": "string",
"status": "pending",
"connection_metadata": {},
"cert_metadata": {},
"created_at": "2026-01-15T12:00:00.000Z"
}Example request
curl -X GET https://api.codespar.dev/v1/connections/{id} \
-H "Authorization: Bearer $CODESPAR_API_KEY"DELETE /v1/connections/{id}
Delete a revoked connection for good
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | ca_-prefixed connection id |
Responses
| Status | Body | Description |
|---|---|---|
204 | — | No Content |
404 | object | Not Found |
409 | object | The connection is still active. Revoke it first. |
Example request
curl -X DELETE https://api.codespar.dev/v1/connections/{id} \
-H "Authorization: Bearer $CODESPAR_API_KEY"POST /v1/connections/{id}/revoke
Revoke a connection and destroy its stored credential
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | ca_-prefixed connection id |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | object | OK |
404 | object | Not Found |
503 | object | The atomic flip and purge failed. Nothing changed; the connection is still usable. Retry. |
Example response
{
"id": "obj_0000000000000000",
"user_id": "user_0000000000000000",
"server_id": "srv_0000000000000000",
"auth_type": "string",
"status": "pending",
"connection_metadata": {},
"cert_metadata": {},
"created_at": "2026-01-15T12:00:00.000Z"
}Example request
curl -X POST https://api.codespar.dev/v1/connections/{id}/revoke \
-H "Authorization: Bearer $CODESPAR_API_KEY"PUT /v1/connections/{id}/webhook-secret
Seed or rotate the secret that verifies this provider's inbound webhooks
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | yes | ca_-prefixed connection id |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
secret | string | yes | — |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | OK |
400 | object | The body did not parse, or the provider has no inbound webhook adapter in this API. |
404 | object | Not Found |
503 | object | The vault write failed. Any previously stored secret is untouched. |
Response 200
| Field | Type | Required | Description |
|---|---|---|---|
connection_id | string | yes | — |
server_id | string | yes | — |
updated | boolean | yes | True when a secret already existed under this ref and was replaced; false when this call seeded the first one. |
Example response
{
"connection_id": "conn_0000000000000000",
"server_id": "srv_0000000000000000",
"updated": true
}Example request
curl -X PUT https://api.codespar.dev/v1/connections/{id}/webhook-secret \
-H "Authorization: Bearer $CODESPAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"secret": "string"
}'