Start here
Quickstart
A key, a call, and a change you can see. About five minutes, and you need nothing installed beyond curl.
1. Create a key
In Octopus, open Settings → Integrations and create an API key. You will be asked to name it and tick the scopes it should hold. For this walkthrough, tick organisation.read and tasks.manage.
The key is shown exactly once
Octopus stores only a hash of it, so it genuinely cannot be shown again, by anyone, including support. Copy it into your secret store before you close the dialog. If you lose it, revoke it and make another.
Keep it in an environment variable rather than pasting it into files:
export OCTOPUS_API_KEY="oct_live_..."2. Confirm it works
Ask the API to describe itself. One call tells you the key is valid, which organisation it belongs to, and exactly which scopes it holds.
curl https://gateway.octopusoperations.co.za/v1 \
-H "Authorization: Bearer $OCTOPUS_API_KEY"{
"success": true,
"version": "v1",
"changeVersion": 1,
"organisation": "4bca402b-e846-4bde-8489-ee894cd80d1c",
"application": "Site reporting bot",
"scopes": [
{ "scope": "organisation.read", "label": "Read the organisation" },
{ "scope": "tasks.manage", "label": "Create and change tasks" },
{ "scope": "tasks.read", "label": "Read tasks" }
],
"realtime": {
"namespace": "/v1",
"how": "Connect a Socket.IO client to this host's /v1 namespace with auth: { apiKey }."
},
"operations": [ "…every endpoint, with a one-line summary" ]
}You asked for two scopes and got three
Asking for a .manage scope also grants the matching .read. Tick tasks.manage and the key is created holding tasks.manage and tasks.read, you never need to ask for both.
3. Read something
Every response uses the same envelope, so one client wrapper covers all of them.
curl https://gateway.octopusoperations.co.za/v1/tasks \
-H "Authorization: Bearer $OCTOPUS_API_KEY"{
"success": true,
"data": [
{
"id": "20269152-383d-4078-a6c6-4ea5a825f1d7",
"orgId": "4bca402b-e846-4bde-8489-ee894cd80d1c",
"projectId": "2ac11d13-9e39-4d29-ad55-c989a32b1a38",
"title": "Inspect scaffolding on level 3",
"status": "todo",
"priority": "high",
"dueDate": "2026-09-30"
}
],
"message": "Found 25 task(s).",
"version": "v1",
"count": 25
}4. Change something
A task belongs to a project, is assigned to somebody, and has a due date. All three are required: a task without them cannot be chased, so Octopus refuses rather than inventing them. Get a project id from GET /v1/projects and a person from GET /v1/personnel.
curl -X POST https://gateway.octopusoperations.co.za/v1/tasks \
-H "Authorization: Bearer $OCTOPUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Inspect scaffolding on level 3",
"projectId": "2ac11d13-9e39-4d29-ad55-c989a32b1a38",
"assigneeId": "abff87b9-6fc2-47d1-9c24-a4e5b012d486",
"dueDate": "2026-09-30",
"priority": "high"
}'The saved record comes back with its id. Change it with a PATCH:
curl -X PATCH https://gateway.octopusoperations.co.za/v1/tasks/20269152-383d-4078-a6c6-4ea5a825f1d7 \
-H "Authorization: Bearer $OCTOPUS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "in_progress" }'5. Watch it happen
That change was just broadcast to anybody subscribed. Here is the whole round trip, including the part you get for free:
Step 2 is the one worth remembering: authorisation happens before anything is changed, so a refused call changes nothing at all. There is no partial write to undo.
Do not poll
Every change you are allowed to see is pushed to the realtime channel and to any webhook you register. Polling costs you rate limit and still arrives later. See the realtime guide.
What next
- Scopes & permissions, what a key can and cannot do, and how refusals read.
- Your first integration: a working script, start to finish.
- API reference, every endpoint, grouped by resource.
