Skip to content

Chainies

Chainies represent long-term objectives that group related chains together.

Endpoints

MethodPathDescriptionAuthRate Limit
GET/chainiesList all chainiesJWT60/min
GET/chainies/:idGet a single chainyJWT60/min
GET/chainies/:id/shareGet sharing infoJWT60/min
POST/chainiesCreate a chainyJWT + Entitlement30/min
PATCH/chainies/:idUpdate a chainyJWT30/min
DELETE/chainies/:idDelete a chainyJWT30/min
PATCH/chainies/:id/statusUpdate chainy statusJWT30/min
POST/chainies/:id/archiveArchive a chainyJWT30/min
POST/chainies/:id/restoreRestore an archived chainyJWT30/min
GET/c/:urlShortResolve a shared chainy by short URLNone or JWT60/min

Create Chainy

Entitlement: productivity.chainy.create

Request

FieldTypeRequiredDescription
titlestringYesChainy title (1–150 chars)
descriptionstringNoLong-form description
categorystringNoOne of: career, health, learning, relationships, finance, creativity, spirituality, other
statusstringNoOne of: active, paused, completed, abandoned, archived
isPublicbooleanNoWhether the chainy is publicly discoverable (default true)
visibilitystringNoprivate | team | public. Setting public enables share URL generation on first PATCH.
colorHexstringNoHex color code in #RRGGBB format (default #10B981)
targetDatestringNoISO 8601 target completion date
instructionstringNoCustom AI instruction for this Chainy. Injected into the AI prompt only at session start.

Response

json
{
  "data": {
    "id": "cm5abc123",
    "title": "Learn Spanish",
    "description": "Achieve B2 fluency in Spanish by end of year",
    "colorHex": "#4A90D9",
    "status": "active",
    "visibility": "private",
    "urlShort": null,
    "targetDate": "2026-12-31T00:00:00.000Z",
    "createdAt": "2026-03-17T10:00:00.000Z"
  }
}

Save data.id — every other endpoint below refers to it as $CHAINY_ID.

Code Examples

bash
curl -X POST https://api.chainabit.com/api/v1/chainies \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Learn Spanish",
    "description": "Achieve B2 fluency in Spanish by end of year",
    "colorHex": "#4A90D9",
    "targetDate": "2026-12-31T00:00:00Z"
  }'
javascript
const BASE_URL = process.env.BASE_URL;
const TOKEN = process.env.TOKEN;

const response = await fetch(`${BASE_URL}/chainies`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    title: "Learn Spanish",
    description: "Achieve B2 fluency in Spanish by end of year",
    colorHex: "#4A90D9",
    targetDate: "2026-12-31T00:00:00Z",
  }),
});
const { data } = await response.json();
python
import requests, os

BASE_URL = os.environ["BASE_URL"]
TOKEN = os.environ["TOKEN"]

response = requests.post(
    f"{BASE_URL}/chainies",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={
        "title": "Learn Spanish",
        "description": "Achieve B2 fluency in Spanish by end of year",
        "colorHex": "#4A90D9",
        "targetDate": "2026-12-31T00:00:00Z",
    },
)
data = response.json()["data"]

Update Chainy Status

Request

FieldTypeRequiredDescription
statusstringYesOne of: active, paused, completed, abandoned, archived

Use the id from Create Chainy's response (data.id) as $CHAINY_ID.

Response

json
{
  "data": {
    "id": "cm5abc123",
    "title": "Learn Spanish",
    "status": "completed",
    "createdAt": "2026-03-17T10:00:00.000Z"
  }
}

Code Examples

bash
curl -X PATCH https://api.chainabit.com/api/v1/chainies/$CHAINY_ID/status \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "completed" }'
javascript
const BASE_URL = process.env.BASE_URL;
const TOKEN = process.env.TOKEN;
const CHAINY_ID = process.env.CHAINY_ID; // from Create Chainy's data.id

const response = await fetch(`${BASE_URL}/chainies/${CHAINY_ID}/status`, {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ status: "completed" }),
});
const { data } = await response.json();
python
import requests, os

response = requests.patch(
    f"{os.environ['BASE_URL']}/chainies/{os.environ['CHAINY_ID']}/status",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
    json={"status": "completed"},
)
data = response.json()["data"]

List Chainies

Request

Response

json
{
  "data": [
    {
      "id": "cm5abc123",
      "title": "Learn Spanish",
      "status": "active",
      "colorHex": "#4A90D9",
      "createdAt": "2026-03-17T10:00:00.000Z"
    }
  ],
  "meta": { "total": 1 }
}

Code Examples

bash
curl https://api.chainabit.com/api/v1/chainies \
  -H "Authorization: Bearer $TOKEN"
javascript
const BASE_URL = process.env.BASE_URL;
const TOKEN = process.env.TOKEN;

const response = await fetch(`${BASE_URL}/chainies`, {
  headers: { Authorization: `Bearer ${TOKEN}` },
});
const { data } = await response.json();
python
import requests, os

response = requests.get(
    f"{os.environ['BASE_URL']}/chainies",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
)
data = response.json()["data"]

Archive / Restore

Request

Response

json
{
  "data": {
    "id": "cm5abc123",
    "status": "archived",
    "createdAt": "2026-03-17T10:00:00.000Z"
  }
}

Code Examples

bash
# Archive
curl -X POST https://api.chainabit.com/api/v1/chainies/$CHAINY_ID/archive \
  -H "Authorization: Bearer $TOKEN"

# Restore
curl -X POST https://api.chainabit.com/api/v1/chainies/$CHAINY_ID/restore \
  -H "Authorization: Bearer $TOKEN"
javascript
const BASE_URL = process.env.BASE_URL;
const TOKEN = process.env.TOKEN;
const CHAINY_ID = process.env.CHAINY_ID; // from Create Chainy's data.id

// Archive
await fetch(`${BASE_URL}/chainies/${CHAINY_ID}/archive`, {
  method: "POST",
  headers: { Authorization: `Bearer ${TOKEN}` },
});

// Restore
await fetch(`${BASE_URL}/chainies/${CHAINY_ID}/restore`, {
  method: "POST",
  headers: { Authorization: `Bearer ${TOKEN}` },
});
python
import requests, os

headers = {"Authorization": f"Bearer {os.environ['TOKEN']}"}

# Archive
requests.post(f"{os.environ['BASE_URL']}/chainies/{os.environ['CHAINY_ID']}/archive", headers=headers)

# Restore
requests.post(f"{os.environ['BASE_URL']}/chainies/{os.environ['CHAINY_ID']}/restore", headers=headers)

Sharing a Chainy

Chainies support three visibility levels:

visibilityWho can access via share URL
privateOwner only
teamWorkspace members only
publicAnyone — no authentication required

When you set visibility to public, a short URL is generated: https://chainabit.com/c/:urlShort. Setting visibility back to private or team permanently deactivates the token — a new one is generated on next publish.

Make a Chainy Public

Set visibility: "public" in a PATCH request. A urlShort token is generated automatically on first publish.

Request

  • Example body:
    json
    { "visibility": "public" }

Response

The response includes urlShort in the chainy object:

json
{
  "data": {
    "id": "cm5abc123",
    "title": "Learn Spanish",
    "visibility": "public",
    "urlShort": "a3f2b9c1e4",
    "createdAt": "2026-03-17T10:00:00.000Z"
  }
}

Code Examples

bash
curl -X PATCH https://api.chainabit.com/api/v1/chainies/$CHAINY_ID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "visibility": "public" }'
javascript
const BASE_URL = process.env.BASE_URL;
const TOKEN = process.env.TOKEN;
const CHAINY_ID = process.env.CHAINY_ID; // from Create Chainy's data.id

const response = await fetch(`${BASE_URL}/chainies/${CHAINY_ID}`, {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ visibility: "public" }),
});
const { data } = await response.json();
// data.urlShort — use this in your share URL
python
import requests, os

response = requests.patch(
    f"{os.environ['BASE_URL']}/chainies/{os.environ['CHAINY_ID']}",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
    json={"visibility": "public"},
)
data = response.json()["data"]
# data["urlShort"]

Get Share Info

Retrieve the current visibility, short token, and full share URL for a chainy you own.

Request

Response

json
{
  "data": {
    "visibility": "public",
    "urlShort": "a3f2b9c1e4",
    "shareUrl": "https://chainabit.com/c/a3f2b9c1e4"
  }
}

Code Examples

bash
curl https://api.chainabit.com/api/v1/chainies/$CHAINY_ID/share \
  -H "Authorization: Bearer $TOKEN"
javascript
const response = await fetch(`${BASE_URL}/chainies/${CHAINY_ID}/share`, {
  headers: { Authorization: `Bearer ${TOKEN}` },
});
const { data } = await response.json();
console.log(data.shareUrl); // https://chainabit.com/c/a3f2b9c1e4
python
import requests, os

response = requests.get(
    f"{os.environ['BASE_URL']}/chainies/{os.environ['CHAINY_ID']}/share",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
)
data = response.json()["data"]
print(data["shareUrl"])

Resolve a Shared Chainy

Access a shared chainy using the short URL. No authentication required for public chainies.

Request

Response

json
{
  "data": {
    "id": "cm5abc123",
    "title": "Learn Spanish",
    "description": "Achieve B2 fluency in Spanish by end of year",
    "visibility": "public",
    "urlShort": "a3f2b9c1e4",
    "status": "active",
    "colorHex": "#4A90D9",
    "createdAt": "2026-03-17T10:00:00.000Z"
  }
}

Private and team chainies return 404 Not Found when accessed without a valid JWT or without the appropriate workspace membership. This applies even when the URL is correct — existence is never confirmed to unauthorized callers.

Code Examples

bash
# Public chainy — no auth needed
curl https://api.chainabit.com/api/v1/c/a3f2b9c1e4

# Private/team chainy — JWT required
curl https://api.chainabit.com/api/v1/c/a3f2b9c1e4 \
  -H "Authorization: Bearer $TOKEN"
javascript
// Public
const response = await fetch(`${BASE_URL}/c/a3f2b9c1e4`);
const { data } = await response.json();

// Private/team
const response = await fetch(`${BASE_URL}/c/a3f2b9c1e4`, {
  headers: { Authorization: `Bearer ${TOKEN}` },
});
const { data } = await response.json();
python
import requests, os

# Public
response = requests.get(f"{os.environ['BASE_URL']}/c/a3f2b9c1e4")

# Private/team
response = requests.get(
    f"{os.environ['BASE_URL']}/c/a3f2b9c1e4",
    headers={"Authorization": f"Bearer {os.environ['TOKEN']}"},
)
data = response.json()["data"]

Regenerate the Share URL

If you want to invalidate the current share URL and create a new one, pass regenerateSlug: true. The previous URL stops working immediately.

Request

  • Example body:
    json
    { "regenerateSlug": true }

Response

Warning: Regenerating the slug immediately invalidates the previous share URL. Anyone who saved the old link will get a 404. Notify collaborators before regenerating.

Code Examples

bash
curl -X PATCH https://api.chainabit.com/api/v1/chainies/$CHAINY_ID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "regenerateSlug": true }'
javascript
await fetch(`${BASE_URL}/chainies/${CHAINY_ID}`, {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ regenerateSlug: true }),
});

Built with purpose.