Skip to main content

Policies

6 operations under /v1/policies (GET POST PATCH DELETE): parameters, status codes, refusal bodies, and the same request in curl, HTTP, Python and TypeScript.

5 min read
View MarkdownEdit on GitHub

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

Every operation below requires a Bearer token. See Authentication.

GET /v1/policies

GEThttps://api.codespar.dev/v1/policies

List policy rules for the authenticated org, sorted by order ASC.

Responses

StatusBodyDescription
200array of PolicyOK
Example request
curl -X GET https://api.codespar.dev/v1/policies \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
GET /v1/policies HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
import os
import requests

res = requests.get(
    "https://api.codespar.dev/v1/policies",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/policies", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.get("/v1/policies");
Example response 200
application/json
[
  {
    "id": "pol_0000000000000000",
    "name": "Example",
    "type": "deny",
    "config": {},
    "agents": [
      "string"
    ],
    "tools": [
      "string"
    ],
    "enabled": true,
    "order": 1,
    "createdAt": "2026-01-15T12:00:00.000Z",
    "updatedAt": "2026-01-15T12:00:00.000Z"
  }
]

POST /v1/policies

POSThttps://api.codespar.dev/v1/policies

Create a new policy rule. A budget rule counts DECLARED intent, not money that left: the cost is added to the agent's daily and monthly counters when the call is evaluated, before anything is sent (the payment amount on consumer payments; for an agent's codespar_pay, the amount of the call; for any other tool on session execute, the caller's estimatedCost). The counters are kept in major units of BRL: a codespar_pay of amount 2500 in BRL counts 25, and the estimatedCost a caller declares beside a codespar_pay is not counted. A codespar_pay in another currency, or with no amount, is allowed and counts nothing, and so does every other outbound meta-tool; the API logs budget rule matched without derivable cost each time a budget rule lets one through. A consumer payment that provably moved nothing (refused before dispatch, or refused by the provider) gives its cost back; one whose outcome is uncertain stays counted. A codespar_pay counted through the meta-tool path is not given back when it fails.

Request body — PolicyCreate

FieldTypeRequiredDescription
agentsarray of stringno—
config—no—
enabledbooleanno—
namestringyes—
toolsarray of stringno—
type"deny" | "budget" | "rate-limit" | "time-window" | "approval-required"yes—

Responses

StatusBodyDescription
201PolicyOK

Response 201

FieldTypeRequiredDescription
agentsarray of stringyes—
configobjectyes—
createdAtstring (date-time)yes—
enabledbooleanyes—
idstringyes—
namestringyes—
ordernumberyes—
toolsarray of stringyes—
type"deny" | "budget" | "rate-limit" | "time-window" | "approval-required"yes—
updatedAtstring (date-time)yes—
Example request
curl -X POST https://api.codespar.dev/v1/policies \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "name": "Example",
       "type": "deny",
       "agents": [],
       "tools": [],
       "enabled": true
     }'
POST /v1/policies HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json

{
  "name": "Example",
  "type": "deny",
  "agents": [],
  "tools": [],
  "enabled": true
}
import os
import requests

res = requests.post(
    "https://api.codespar.dev/v1/policies",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
    json={
      "name": "Example",
      "type": "deny",
      "agents": [],
      "tools": [],
      "enabled": True
    },
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/policies", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Example",
    "type": "deny",
    "agents": [],
    "tools": [],
    "enabled": true
  }),
});

const data = await res.json();
const result = await cs.api.post("/v1/policies", {
  body: {
    name: "Example",
    type: "deny",
    agents: [],
    tools: [],
    enabled: true
  }
});
Example response 201
application/json
{
  "id": "pol_0000000000000000",
  "name": "Example",
  "type": "deny",
  "config": {},
  "agents": [
    "string"
  ],
  "tools": [
    "string"
  ],
  "enabled": true,
  "order": 1,
  "createdAt": "2026-01-15T12:00:00.000Z",
  "updatedAt": "2026-01-15T12:00:00.000Z"
}

POST /v1/policies/reorder

POSThttps://api.codespar.dev/v1/policies/reorder

Reorder policy rules. Atomic: if any id does not belong to the org, the entire operation rolls back and returns 404.

Request body — PolicyReorder

FieldTypeRequiredDescription
idsarray of stringyes—

Responses

StatusBodyDescription
204—No Content
404objectNot Found
Example request
curl -X POST https://api.codespar.dev/v1/policies/reorder \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "ids": [
         "string"
       ]
     }'
POST /v1/policies/reorder HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json

{
  "ids": [
    "string"
  ]
}
import os
import requests

res = requests.post(
    "https://api.codespar.dev/v1/policies/reorder",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
    json={
      "ids": [
        "string"
      ]
    },
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/policies/reorder", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "ids": [
      "string"
    ]
  }),
});

const data = await res.json();
const result = await cs.api.post("/v1/policies/reorder", {
  body: {
    ids: [
      "string"
    ]
  }
});

GET /v1/policies/{id}

GEThttps://api.codespar.dev/v1/policies/{id}

Read one policy rule

The same row the list returns, by id. 404 when the id belongs to another org: the org predicate excludes it from the query, so the handler cannot tell 'other tenant' from 'absent' — and must not, because telling them apart leaks existence.

Responses

StatusBodyDescription
200PolicyOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
agentsarray of stringyes—
configobjectyes—
createdAtstring (date-time)yes—
enabledbooleanyes—
idstringyes—
namestringyes—
ordernumberyes—
toolsarray of stringyes—
type"deny" | "budget" | "rate-limit" | "time-window" | "approval-required"yes—
updatedAtstring (date-time)yes—
Example request
curl -X GET https://api.codespar.dev/v1/policies/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
GET /v1/policies/{id} HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
import os
import requests

res = requests.get(
    "https://api.codespar.dev/v1/policies/{id}",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/policies/{id}", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.get("/v1/policies/{id}");
Example response 200
application/json
{
  "id": "pol_0000000000000000",
  "name": "Example",
  "type": "deny",
  "config": {},
  "agents": [
    "string"
  ],
  "tools": [
    "string"
  ],
  "enabled": true,
  "order": 1,
  "createdAt": "2026-01-15T12:00:00.000Z",
  "updatedAt": "2026-01-15T12:00:00.000Z"
}

PATCH /v1/policies/{id}

PATCHhttps://api.codespar.dev/v1/policies/{id}

Update a policy rule. Cross-org ids return 404. Invalidates the per-org cache on success.

Path parameters

NameTypeRequiredDescription
idstringyes—

Request body — PolicyUpdate

FieldTypeRequiredDescription
agentsarray of stringno—
config—no—
enabledbooleanno—
namestringno—
toolsarray of stringno—
type"deny" | "budget" | "rate-limit" | "time-window" | "approval-required"no—

Responses

StatusBodyDescription
200PolicyOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
agentsarray of stringyes—
configobjectyes—
createdAtstring (date-time)yes—
enabledbooleanyes—
idstringyes—
namestringyes—
ordernumberyes—
toolsarray of stringyes—
type"deny" | "budget" | "rate-limit" | "time-window" | "approval-required"yes—
updatedAtstring (date-time)yes—
Example request
curl -X PATCH https://api.codespar.dev/v1/policies/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "name": "Example",
       "type": "deny",
       "agents": [
         "string"
       ],
       "tools": [
         "string"
       ],
       "enabled": true
     }'
PATCH /v1/policies/{id} HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
Content-Type: application/json

{
  "name": "Example",
  "type": "deny",
  "agents": [
    "string"
  ],
  "tools": [
    "string"
  ],
  "enabled": true
}
import os
import requests

res = requests.patch(
    "https://api.codespar.dev/v1/policies/{id}",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
    json={
      "name": "Example",
      "type": "deny",
      "agents": [
        "string"
      ],
      "tools": [
        "string"
      ],
      "enabled": True
    },
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/policies/{id}", {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Example",
    "type": "deny",
    "agents": [
      "string"
    ],
    "tools": [
      "string"
    ],
    "enabled": true
  }),
});

const data = await res.json();
const result = await cs.api.patch("/v1/policies/{id}", {
  path: {
    id: "policie_0000000000000000"
  },
  body: {
    name: "Example",
    type: "deny",
    agents: [
      "string"
    ],
    tools: [
      "string"
    ],
    enabled: true
  }
});
Example response 200
application/json
{
  "id": "pol_0000000000000000",
  "name": "Example",
  "type": "deny",
  "config": {},
  "agents": [
    "string"
  ],
  "tools": [
    "string"
  ],
  "enabled": true,
  "order": 1,
  "createdAt": "2026-01-15T12:00:00.000Z",
  "updatedAt": "2026-01-15T12:00:00.000Z"
}

DELETE /v1/policies/{id}

DELETEhttps://api.codespar.dev/v1/policies/{id}

Delete a policy rule. Cross-org ids return 404. Invalidates the per-org cache on success.

Path parameters

NameTypeRequiredDescription
idstringyes—

Responses

StatusBodyDescription
204—No Content
404objectNot Found
Example request
curl -X DELETE https://api.codespar.dev/v1/policies/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
DELETE /v1/policies/{id} HTTP/1.1
Host: api.codespar.dev
Authorization: Bearer $CODESPAR_API_KEY
import os
import requests

res = requests.delete(
    "https://api.codespar.dev/v1/policies/{id}",
    headers={"Authorization": f"Bearer {os.environ['CODESPAR_API_KEY']}"},
)
res.raise_for_status()
data = res.json()
const res = await fetch("https://api.codespar.dev/v1/policies/{id}", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.delete("/v1/policies/{id}", {
  path: {
    id: "policie_0000000000000000"
  }
});
Policies | CodeSpar