Quickstart

Four steps from zero to a created contact: mint a key, verify it, discover what it can do, and run your first action. Every step is shown in curl, JavaScript and Python — pick one column and paste.

1. Create an API key

In the app, open Developers and create a key. It looks like chp_live_… and is displayed exactly once at creation — Chirply stores only its hash. The key acts with owner-level access for its workspace, so keep it in a secret store the way you would a password.

Shell
# Keep the key out of your shell history and your source tree.
export CHIRPLY_API_KEY="chp_live_…"

2. Verify it — whoami

GET /api/v1 is the cheapest authenticated read: it answers with the workspace the credential acts for, the scopes it holds, and where everything else lives. Integrators health-check on it, and it returns the RateLimit-* headers so you can watch your budget.

curl
curl https://app.chirply.io/api/v1 \
  -H "Authorization: Bearer $CHIRPLY_API_KEY"
JavaScript (fetch)
const res = await fetch("https://app.chirply.io/api/v1", {
  headers: { Authorization: `Bearer ${process.env.CHIRPLY_API_KEY}` },
});
const { data } = await res.json();
console.log(data.org_id, data.scopes, data.actions.total);
Python (requests)
import os
import requests

res = requests.get(
    "https://app.chirply.io/api/v1",
    headers={"Authorization": f"Bearer {os.environ['CHIRPLY_API_KEY']}"},
)
data = res.json()["data"]
print(data["org_id"], data["scopes"], data["actions"]["total"])
Response (abridged)
{
  "data": {
    "api": "chirply",
    "version": "v1",
    "org_id": "…",
    "scopes": ["read", "write"],
    "resources": ["contacts", "deals", "tasks"],
    "actions": {
      "total": …,
      "catalog_url": "/api/v1/actions",
      "run_url": "/api/v1/actions/{name}"
    },
    "mcp_url": "/api/mcp"
  }
}

actions.total is live — it is the number of operations this key can reach, read from the same registry the app runs on.

3. Discover the catalog

GET /api/v1/actions lists every action your key may perform, each with its description and a JSON Schema for its arguments. Read it once and you know the whole API without a hand-written client. Filter with ?domain=contacts, ?scope=write or ?q=invoice, and page with ?limit= (up to 100) and ?offset=.

curl
curl "https://app.chirply.io/api/v1/actions?domain=contacts" \
  -H "Authorization: Bearer $CHIRPLY_API_KEY"
JavaScript (fetch)
const res = await fetch("https://app.chirply.io/api/v1/actions?domain=contacts", {
  headers: { Authorization: `Bearer ${process.env.CHIRPLY_API_KEY}` },
});
const { data } = await res.json();
for (const action of data.actions) {
  console.log(action.name, "—", action.title);
}
Python (requests)
res = requests.get(
    "https://app.chirply.io/api/v1/actions",
    params={"domain": "contacts"},
    headers={"Authorization": f"Bearer {os.environ['CHIRPLY_API_KEY']}"},
)
for action in res.json()["data"]["actions"]:
    print(action["name"], "—", action["title"])

One action’s full description — title, risk, argument schema — is GET /api/v1/actions/<name>. The same list is browsable without a key in the actions reference.

4. Run your first action

Every operation is one POST. The name is <domain>.<verb> and the body is the operation’s input object — here, contacts.create.

curl
curl -X POST https://app.chirply.io/api/v1/actions/contacts.create \
  -H "Authorization: Bearer $CHIRPLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"first_name":"Ada","last_name":"Lovelace","phone":"+15551234567"}'
JavaScript (fetch)
const res = await fetch("https://app.chirply.io/api/v1/actions/contacts.create", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CHIRPLY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    first_name: "Ada",
    last_name: "Lovelace",
    phone: "+15551234567",
  }),
});
const { data } = await res.json();
console.log(data.summary);
Python (requests)
res = requests.post(
    "https://app.chirply.io/api/v1/actions/contacts.create",
    headers={"Authorization": f"Bearer {os.environ['CHIRPLY_API_KEY']}"},
    json={
        "first_name": "Ada",
        "last_name": "Lovelace",
        "phone": "+15551234567",
    },
)
print(res.json()["data"]["summary"])
Response
{
  "data": {
    "action": "contacts.create",
    "summary": "…a one-line human-readable account of what happened…",
    "result": { …the created record… }
  }
}

Actions marked confirm do real things

Operations that spend money, send messages to real people, or destroy data carry risk: "confirm" in the catalog. Holding a credential is itself the confirmation for API and MCP callers — the in-app assistant is the surface that asks a human first — so read an action’s description before wiring it into a loop.