API REFERENCE v1

DEVELOPERS

AI apps

The Live request object

AI apps connected over MCP (OAuth), and live requests waiting for a human.

ATTRIBUTES

  • object enum
    • live_request
  • id string
  • action enum

    The operation (LiveRequestCreate lists each one with its params).

    • create_live_api_key
    • publish_flow_live
    • set_billing_source
    • create_webhook_endpoint
    • update_webhook_endpoint
    • delete_webhook_endpoint
    • test_webhook_endpoint
    • create_attribute_definition
    • update_attribute_definition
    • create_customer
    • update_customer
    • set_customer_attributes
    • record_usage_event
    • record_usage_events
    • create_subscription
    • update_subscription
    • record_payment
  • title string

    The operation's name, e.g. Add a live webhook endpoint.

  • summary string

    What approving does, written by NoChurn from the params (never by the AI app).

  • params object

    The operation's params as checked by NoChurn (LiveRequestParams*), e.g. a customer reference resolved to its cst_… id.

  • precondition object | null

    What must still hold at approval, else the request fails without acting.

    Show child attributesHide child attributes
    • kind enum
      • draft_digest
      • current_value
      • record_version
      • record_exists
    • object string | null

      flow, billing_source, webhook_endpoint, attribute_definition, customer, subscription

    • id string | null
    • expected string | null

      current_value only: the value when the app asked.

    • status enum | null

      Pending requests only: checked now.

      • holds
      • changed
    • description string
  • reason string | null

    Written by the AI app: untrusted text, show it as text.

Show 11 more attributesHide 11 attributes
  • status enum
    • pending
    • approved
    • rejected
    • expired
    • failed
  • requested_by object
    Show child attributesHide child attributes
  • approval_url string

    Dashboard page where an owner or admin approves or rejects it.

  • decided_by object | null
    Show child attributesHide child attributes
  • decided_at string | null date-time
  • result object

    What the approval produced: object and id only (plus api_key_id, flow_version_id, billing_source for the first three operations). Never live data.

  • error string | null

    failed: why the action did not run.

  • api_key object | null

    Approval of create_live_api_key only: the new live key with its secret, shown once to the approver.

    Show child attributesHide child attributes
  • response object | null

    Approval answer only, to the approver: the operation's API response (it may hold a secret shown once: a live key's token, a webhook endpoint's signing secret). Never stored.

  • expires_at string date-time
  • created_at string date-time

Schema: LiveRequest

THE LIVE REQUEST OBJECT
{
  "object": "live_request",
  "id": "lrq_FpLTMa8X3rjugaNz",
  "action": "create_live_api_key",
  "title": "Create a live API key",
  "summary": "Create a live secret (nc_live_…) API key named “Production server”, full access",
  "params": {
    "kind": "secret",
    "name": "Production server",
    "access": "full",
    "permissions": {}
  },
  "precondition": null,
  "reason": "Ready for production",
  "status": "approved",
  "requested_by": {
    "type": "ai_agent",
    "name": "Claude Code",
    "grant_id": "ogr_TH3UBPgpw5dZYQcm"
  },
  "approval_url": "http://localhost:5173/live-requests/lrq_FpLTMa8X3rjugaNz?account=acc_SHWzbh3KJWUUN6ez",
  "decided_by": {
    "id": "usr_4NwxZDGRUAd3xyBn",
    "email": "user1@example.test"
  },
  "decided_at": "2026-11-04T10:00:00.000Z",
  "result": {
    "object": "api_key",
    "id": "key_wjS3tDF9X8143ppr",
    "api_key_id": "key_wjS3tDF9X8143ppr"
  },
  "error": null,
  "api_key": {
    "object": "api_key",
    "id": "key_wjS3tDF9X8143ppr",
    "name": "Production server",
    "kind": "secret",
    "mode": "live",
    "access": "full",
    "permissions": {
      "account": "write",
      "api_keys": "write",
      "team": "write",
      "events": "write",
      "customers": "write",
      "billing": "write",
      "stripe_connections": "write",
      "logs": "write",
      "flows": "write",
      "email_domains": "write",
      "messages": "write",
      "webhooks": "write",
      "cancel_sessions": "write",
      "reviews": "write",
      "dashboard": "write",
      "insights": "write",
      "integrations": "write",
      "queries": "write",
      "disputes": "write",
      "sandbox": "write"
    },
    "last4": "QbM5",
    "allowed_origins": null,
    "token": "nc_live_EXAMPLE00000000000000000",
    "first_used_at": null,
    "last_used_at": null,
    "revoked_at": null,
    "created_at": "2026-11-04T10:00:00.000Z"
  },
  "response": {
    "object": "api_key",
    "id": "key_wjS3tDF9X8143ppr",
    "name": "Production server",
    "kind": "secret",
    "mode": "live",
    "access": "full",
    "permissions": {
      "account": "write",
      "api_keys": "write",
      "team": "write",
      "events": "write",
      "customers": "write",
      "billing": "write",
      "stripe_connections": "write",
      "logs": "write",
      "flows": "write",
      "email_domains": "write",
      "messages": "write",
      "webhooks": "write",
      "cancel_sessions": "write",
      "reviews": "write",
      "dashboard": "write",
      "insights": "write",
      "integrations": "write",
      "queries": "write",
      "disputes": "write",
      "sandbox": "write"
    },
    "last4": "QbM5",
    "allowed_origins": null,
    "token": "nc_live_EXAMPLE00000000000000000",
    "first_used_at": null,
    "last_used_at": null,
    "revoked_at": null,
    "created_at": "2026-11-04T10:00:00.000Z"
  },
  "expires_at": "2026-11-11T10:00:00.000Z",
  "created_at": "2026-11-04T10:00:00.000Z"
}

Ask a human to do something in live mode (AI apps)

OAuth tokens only (configure scope, plus the scope the operation needs in test mode: sandbox for customers, usage, subscriptions and payments). AI apps never change live mode directly: they ask for one operation (action) with its params (one schema per operation, see LiveRequestCreate) and give approval_url to an owner or admin. NoChurn checks the params, looks the target up in live mode, writes its own summary and captures what must still hold at approval (precondition). Nothing runs until a human approves it in the dashboard; it then runs in live mode as that human. Asked in any mode (the NoChurn-Mode header is ignored here). The same pending request asked again is returned as is. Never possible: the team, AI app access, 2FA, NoChurn's own plan, editing or revoking existing keys, deleting the account.

  • AI apps only: an OAuth access token (ncat_…) with the configure scope. An API key is refused (403).

BODY PARAMETERS

One of:

  • action enum REQUIRED
    • create_live_api_key
  • params object REQUIRED

    Params of create_live_api_key: Create a live API key.

    Show child parametersHide child parameters
  • reason string 1000 characters at most

    Shown to the human as the app's note (untrusted text).

RETURNS

ERRORS

POST/v1/live_requests
curl https://api.nochurn.sh/v1/live_requests \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "create_live_api_key",
    "params": {
      "name": "Production server"
    },
    "reason": "Integration verified in test mode"
  }'
const res = await fetch("https://api.nochurn.sh/v1/live_requests", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "action": "create_live_api_key",
    "params": {
      "name": "Production server"
    },
    "reason": "Integration verified in test mode"
  }),
});
const liveRequest = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/live_requests",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={
      "action": "create_live_api_key",
      "params": {
        "name": "Production server"
      },
      "reason": "Integration verified in test mode"
    },
)
live_request = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/live_requests")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
  "action" => "create_live_api_key",
  "params" => {
    "name" => "Production server"
  },
  "reason" => "Integration verified in test mode"
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
live_request = JSON.parse(res.body)
RESPONSE 201
{
  "object": "live_request",
  "id": "lrq_7y3fem7wpcHdUx1s",
  "action": "create_live_api_key",
  "title": "Create a live API key",
  "summary": "Create a live secret (nc_live_…) API key named “Production server”, full access",
  "params": {
    "name": "Production server",
    "kind": "secret",
    "access": "full",
    "permissions": {}
  },
  "precondition": null,
  "reason": "Integration verified in test mode",
  "status": "pending",
  "requested_by": {
    "type": "ai_agent",
    "name": "Claude Code",
    "grant_id": "ogr_A9AUMTA8qUFrqLLZ"
  },
  "approval_url": "http://localhost:5173/live-requests/lrq_7y3fem7wpcHdUx1s?account=acc_itN4DgVRL8A9caPs",
  "decided_by": null,
  "decided_at": null,
  "result": {},
  "error": null,
  "api_key": null,
  "response": null,
  "expires_at": "2026-11-11T10:00:00.000Z",
  "created_at": "2026-11-04T10:00:00.000Z"
}

Retrieve a live request

AI apps poll it to know whether a human approved.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): read scope.

PATH PARAMETERS

  • id string REQUIRED

RETURNS

GET/v1/live_requests/{id}
curl https://api.nochurn.sh/v1/live_requests/lrq_a29dDA8tYCJq8KTP \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/live_requests/lrq_a29dDA8tYCJq8KTP", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const liveRequest = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/live_requests/lrq_a29dDA8tYCJq8KTP",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
live_request = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/live_requests/lrq_a29dDA8tYCJq8KTP")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
live_request = JSON.parse(res.body)
RESPONSE 200
{
  "object": "live_request",
  "id": "lrq_a29dDA8tYCJq8KTP",
  "action": "publish_flow_live",
  "title": "Publish a flow to live mode",
  "summary": "Publish the current draft of Cancel flow to live mode (customers in live mode get it)",
  "params": {
    "flow_id": "flw_K13CEko818VgKSAc",
    "flow_kind": "cancel",
    "flow_name": "Cancel flow"
  },
  "precondition": {
    "kind": "draft_digest",
    "object": "flow",
    "id": "flw_K13CEko818VgKSAc",
    "expected": null,
    "status": "holds",
    "description": "The flow draft must be the one the app asked to publish."
  },
  "reason": "Ready for production",
  "status": "pending",
  "requested_by": {
    "type": "ai_agent",
    "name": "Claude Code",
    "grant_id": "ogr_CxuaJ9mcH429DzBw"
  },
  "approval_url": "http://localhost:5173/live-requests/lrq_a29dDA8tYCJq8KTP?account=acc_ptg1cVcxU237ywmi",
  "decided_by": null,
  "decided_at": null,
  "result": {},
  "error": null,
  "api_key": null,
  "response": null,
  "expires_at": "2026-11-11T10:00:00.000Z",
  "created_at": "2026-11-04T10:00:00.000Z"
}

List live requests

An AI app sees its own requests; the dashboard sees every request of the account.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): read scope.

QUERY PARAMETERS

RETURNS

GET/v1/live_requests
curl https://api.nochurn.sh/v1/live_requests \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/live_requests", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const page = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/live_requests",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
page = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/live_requests")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
page = JSON.parse(res.body)
RESPONSE 200
{
  "object": "list",
  "data": [
    {
      "object": "live_request",
      "id": "lrq_x1S3mBZzebRmeJkX",
      "action": "set_billing_source",
      "title": "Change the billing source",
      "summary": "Set the billing source to your own billing (API) (test and live modes)",
      "params": {
        "billing_source": "api"
      },
      "precondition": {
        "kind": "current_value",
        "object": "billing_source",
        "id": null,
        "expected": "stripe",
        "status": "holds",
        "description": "The billing source must still be stripe."
      },
      "reason": "Ready for production",
      "status": "pending",
      "requested_by": {
        "type": "ai_agent",
        "name": "Claude Code",
        "grant_id": "ogr_9Gp8DnTNkPEsTAAU"
      },
      "approval_url": "http://localhost:5173/live-requests/lrq_x1S3mBZzebRmeJkX?account=acc_n31kFwAhaVTBRdpZ",
      "decided_by": null,
      "decided_at": null,
      "result": {},
      "error": null,
      "api_key": null,
      "response": null,
      "expires_at": "2026-11-11T10:00:00.000Z",
      "created_at": "2026-11-04T10:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Approve a live request (dashboard, owner or admin)

Runs the operation now, as the approver, in live mode (its Events carry via: the AI app). Its API answer is returned once, to the approver only, in response (and api_key for create_live_api_key): a live key's token, a webhook endpoint's signing secret. Fails (status failed, error) without changing anything if the precondition no longer holds or the operation is refused.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

HEADER PARAMETERS

RETURNS

ERRORS

POST/v1/live_requests/{id}/approve
curl https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/approve \
  -X POST \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/approve", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const liveRequest = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/approve",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
live_request = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/approve")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
live_request = JSON.parse(res.body)
RESPONSE 200
{
  "object": "live_request",
  "id": "lrq_FpLTMa8X3rjugaNz",
  "action": "create_live_api_key",
  "title": "Create a live API key",
  "summary": "Create a live secret (nc_live_…) API key named “Production server”, full access",
  "params": {
    "kind": "secret",
    "name": "Production server",
    "access": "full",
    "permissions": {}
  },
  "precondition": null,
  "reason": "Ready for production",
  "status": "approved",
  "requested_by": {
    "type": "ai_agent",
    "name": "Claude Code",
    "grant_id": "ogr_TH3UBPgpw5dZYQcm"
  },
  "approval_url": "http://localhost:5173/live-requests/lrq_FpLTMa8X3rjugaNz?account=acc_SHWzbh3KJWUUN6ez",
  "decided_by": {
    "id": "usr_4NwxZDGRUAd3xyBn",
    "email": "user1@example.test"
  },
  "decided_at": "2026-11-04T10:00:00.000Z",
  "result": {
    "object": "api_key",
    "id": "key_wjS3tDF9X8143ppr",
    "api_key_id": "key_wjS3tDF9X8143ppr"
  },
  "error": null,
  "api_key": {
    "object": "api_key",
    "id": "key_wjS3tDF9X8143ppr",
    "name": "Production server",
    "kind": "secret",
    "mode": "live",
    "access": "full",
    "permissions": {
      "account": "write",
      "api_keys": "write",
      "team": "write",
      "events": "write",
      "customers": "write",
      "billing": "write",
      "stripe_connections": "write",
      "logs": "write",
      "flows": "write",
      "email_domains": "write",
      "messages": "write",
      "webhooks": "write",
      "cancel_sessions": "write",
      "reviews": "write",
      "dashboard": "write",
      "insights": "write",
      "integrations": "write",
      "queries": "write",
      "disputes": "write",
      "sandbox": "write"
    },
    "last4": "QbM5",
    "allowed_origins": null,
    "token": "nc_live_EXAMPLE00000000000000000",
    "first_used_at": null,
    "last_used_at": null,
    "revoked_at": null,
    "created_at": "2026-11-04T10:00:00.000Z"
  },
  "response": {
    "object": "api_key",
    "id": "key_wjS3tDF9X8143ppr",
    "name": "Production server",
    "kind": "secret",
    "mode": "live",
    "access": "full",
    "permissions": {
      "account": "write",
      "api_keys": "write",
      "team": "write",
      "events": "write",
      "customers": "write",
      "billing": "write",
      "stripe_connections": "write",
      "logs": "write",
      "flows": "write",
      "email_domains": "write",
      "messages": "write",
      "webhooks": "write",
      "cancel_sessions": "write",
      "reviews": "write",
      "dashboard": "write",
      "insights": "write",
      "integrations": "write",
      "queries": "write",
      "disputes": "write",
      "sandbox": "write"
    },
    "last4": "QbM5",
    "allowed_origins": null,
    "token": "nc_live_EXAMPLE00000000000000000",
    "first_used_at": null,
    "last_used_at": null,
    "revoked_at": null,
    "created_at": "2026-11-04T10:00:00.000Z"
  },
  "expires_at": "2026-11-11T10:00:00.000Z",
  "created_at": "2026-11-04T10:00:00.000Z"
}

Reject a live request (dashboard, owner or admin)

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

HEADER PARAMETERS

RETURNS

POST/v1/live_requests/{id}/reject
curl https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/reject \
  -X POST \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/reject", {
  method: "POST",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const liveRequest = await res.json();
import requests

res = requests.post(
    "https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/reject",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
live_request = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/live_requests/lrq_x1S3mBZzebRmeJkX/reject")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
live_request = JSON.parse(res.body)
RESPONSE 200
{
  "object": "live_request",
  "id": "lrq_qjEB7xxu8ZAoUT4y",
  "action": "publish_flow_live",
  "title": "Publish a flow to live mode",
  "summary": "Publish the current draft of Cancel flow to live mode (customers in live mode get it)",
  "params": {
    "flow_id": "flw_pr839pHikX4wkNpw",
    "flow_kind": "cancel",
    "flow_name": "Cancel flow"
  },
  "precondition": {
    "kind": "draft_digest",
    "object": "flow",
    "id": "flw_pr839pHikX4wkNpw",
    "expected": null,
    "status": null,
    "description": "The flow draft must be the one the app asked to publish."
  },
  "reason": "Ready for production",
  "status": "rejected",
  "requested_by": {
    "type": "ai_agent",
    "name": "Claude Code",
    "grant_id": "ogr_cpYehACptMsaMRM6"
  },
  "approval_url": "http://localhost:5173/live-requests/lrq_qjEB7xxu8ZAoUT4y?account=acc_E8fCBPuUNqCUVdoq",
  "decided_by": {
    "id": "usr_GPLLsThB1vdVkV4j",
    "email": "user1@example.test"
  },
  "decided_at": "2026-11-04T10:00:00.000Z",
  "result": {},
  "error": null,
  "api_key": null,
  "response": null,
  "expires_at": "2026-11-11T10:00:00.000Z",
  "created_at": "2026-11-04T10:00:00.000Z"
}

List the AI apps connected to the account

Settings › Connected AI apps: MCP clients authorized through OAuth, with their scopes and last use.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need read access.
  • AI apps (OAuth): not available.

QUERY PARAMETERS

RETURNS

GET/v1/oauth/grants
curl https://api.nochurn.sh/v1/oauth/grants \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/oauth/grants", {
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const page = await res.json();
import requests

res = requests.get(
    "https://api.nochurn.sh/v1/oauth/grants",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
page = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/oauth/grants")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
page = JSON.parse(res.body)
RESPONSE 200
{
  "object": "list",
  "data": [
    {
      "object": "oauth_grant",
      "id": "ogr_ga9szsdYbQPGuhay",
      "client": {
        "id": "mcpc_8NeN1E6YEpZvJ7vh",
        "name": "Cursor",
        "verified": false,
        "verified_name": null,
        "client_uri": null
      },
      "user": {
        "id": "usr_DgKVbPfoFB5vggGt",
        "email": "user1@example.test",
        "name": "User"
      },
      "scopes": ["read", "configure", "sandbox"],
      "live_read": false,
      "live_write": "approval_required",
      "last_used_at": null,
      "revoked_at": null,
      "created_at": "2026-11-04T10:00:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Allow or stop an AI app's live reads

live_read: whether the app may read live data (NoChurn-Mode: live, reads only). Owner or admin, or the member who connected it. Turning it on needs a person in a dashboard session (never an API key or an OAuth token); turning it off works from any of them. Every change writes an Event.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

HEADER PARAMETERS

BODY PARAMETERS

RETURNS

ERRORS

  • 403 forbidden turning live reads on with an API key
PATCH/v1/oauth/grants/{id}
curl https://api.nochurn.sh/v1/oauth/grants/ogr_s9Y7BkukioSRcJSa \
  -X PATCH \
  -H "Authorization: Bearer nc_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "live_read": true
  }'
const res = await fetch("https://api.nochurn.sh/v1/oauth/grants/ogr_s9Y7BkukioSRcJSa", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer nc_test_…",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "live_read": true
  }),
});
const oauthGrant = await res.json();
import requests

res = requests.patch(
    "https://api.nochurn.sh/v1/oauth/grants/ogr_s9Y7BkukioSRcJSa",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
    json={
      "live_read": True
    },
)
oauth_grant = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/oauth/grants/ogr_s9Y7BkukioSRcJSa")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer nc_test_…"
req["Content-Type"] = "application/json"
req.body = {
  "live_read" => true
}.to_json

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
oauth_grant = JSON.parse(res.body)
RESPONSE 200
{
  "object": "oauth_grant",
  "id": "ogr_s9Y7BkukioSRcJSa",
  "client": {
    "id": "mcpc_JGFoYmVEQ9hSQq9T",
    "name": "Cursor",
    "verified": false,
    "verified_name": null,
    "client_uri": null
  },
  "user": {
    "id": "usr_Znx8PDYTc71YL9kP",
    "email": "user2@example.test",
    "name": "User"
  },
  "scopes": ["read", "configure", "sandbox"],
  "live_read": true,
  "live_write": "approval_required",
  "last_used_at": null,
  "revoked_at": null,
  "created_at": "2026-11-04T10:00:00.000Z"
}

Revoke an AI app's access

Every token of the app stops working at once, and its pending live requests are cancelled (status expired, with the reason in error and a live_request.expired Event). Owner or admin, or the member who connected it.

  • Secret key (nc_test_… or nc_live_…). Restricted keys need write access.
  • AI apps (OAuth): not available.

PATH PARAMETERS

  • id string REQUIRED

HEADER PARAMETERS

RETURNS

ERRORS

DELETE/v1/oauth/grants/{id}
curl https://api.nochurn.sh/v1/oauth/grants/ogr_aAN5xuUxRriy3UW2 \
  -X DELETE \
  -H "Authorization: Bearer nc_test_…"
const res = await fetch("https://api.nochurn.sh/v1/oauth/grants/ogr_aAN5xuUxRriy3UW2", {
  method: "DELETE",
  headers: {
    Authorization: "Bearer nc_test_…",
  },
});
const oauthGrant = await res.json();
import requests

res = requests.delete(
    "https://api.nochurn.sh/v1/oauth/grants/ogr_aAN5xuUxRriy3UW2",
    headers={
        "Authorization": "Bearer nc_test_…",
    },
)
oauth_grant = res.json()
require "net/http"
require "json"

uri = URI("https://api.nochurn.sh/v1/oauth/grants/ogr_aAN5xuUxRriy3UW2")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer nc_test_…"

res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
oauth_grant = JSON.parse(res.body)
RESPONSE 200
{
  "object": "oauth_grant",
  "id": "ogr_aAN5xuUxRriy3UW2",
  "client": {
    "id": "mcpc_bvMfrNFty8PB8882",
    "name": "Cursor",
    "verified": false,
    "verified_name": null,
    "client_uri": null
  },
  "user": {
    "id": "usr_8FSUTy7n5pyHtBp9",
    "email": "user2@example.test",
    "name": "User"
  },
  "scopes": ["read", "configure", "sandbox"],
  "live_read": false,
  "live_write": "approval_required",
  "last_used_at": null,
  "revoked_at": "2026-11-04T10:00:00.000Z",
  "created_at": "2026-11-04T10:00:00.000Z"
}