Quickstart
This page takes you from nothing to a decision in your terminal. You need an organization with at least one operator who has claimed a box.
-
Generate an API key
Section titled “Generate an API key”In the dashboard, open your organization’s keys page and generate a key with the
proposeandreadscopes. The secret is shown once, so store it before you leave the page.export OUTIS_KEY=<the token you just generated> -
Create a request
Section titled “Create a request”Every organization starts with the GitHub integration’s actions, so
deploy.productionworks on a fresh one.curl -X POST "https://api.outis.tech/v1/requests" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $OUTIS_KEY" \ -H "Idempotency-Key: quickstart-8d93f71" \ -d '{ "action": "deploy.production", "requester": "keith", "params": { "repo": "acme/payments-api", "env": "production", "sha": "8d93f71" } }'import { Outis } from "@outis/sdk"; const outis = new Outis({ apiKey: process.env.OUTIS_KEY }); const request = await outis.requests.create( { action: "deploy.production", requester: "keith", params: { repo: "acme/payments-api", env: "production", sha: "8d93f71" }, }, { idempotencyKey: "quickstart-8d93f71" }, ); console.log(request.id, request.operationHash);import os from outis import Outis outis = Outis(api_key=os.environ["OUTIS_KEY"]) request = outis.requests.create( action="deploy.production", requester="keith", params={"repo": "acme/payments-api", "env": "production", "sha": "8d93f71"}, idempotency_key="quickstart-8d93f71", ) print(request.id, request.operation_hash)client := outis.New(os.Getenv("OUTIS_KEY")) req, err := client.Requests.Create(ctx, outis.CreateParams{ Action: "deploy.production", Requester: "keith", Params: map[string]string{"repo": "acme/payments-api", "env": "production", "sha": "8d93f71"}, }, outis.WithIdempotencyKey("quickstart-8d93f71")) if err != nil { return err } fmt.Println(req.ID, req.OperationHash)The answer is a 202 with the request itself, the same body you’ll read the decision from:
{ "server_now": <epoch ms>, "request": { "id": "req-4f2a9c1b8d7e6f50", "action": "deploy.production", "requester": "keith", "operation_hash": "sha256:54feb247e0ae56c01d430beb1b1c4c604384ca91832a1ccb435fe2753fb2be9e", "state": "notified", "live": true, "outcome": null, "approvers": [], "params": { "repo": "acme/payments-api", "env": "production", "sha": "8d93f71" }, "created_at": <epoch ms>, "decided_at": null } }The eligible operators now have their codes, and their boxes are drawing the request. Run the same call again and you get the same request back, because the
Idempotency-Keymatches. -
Turn a key
Section titled “Turn a key”An operator enters their code on the box and turns the key. For
deploy.productionthat’s two operators inside one twenty second window, neither of them the requester. -
Read the decision
Section titled “Read the decision”curl "https://api.outis.tech/v1/requests/req-4f2a9c1b8d7e6f50" \ -H "Authorization: Bearer $OUTIS_KEY"const decided = await outis.requests.assertAuthorized(request.id, { action: "deploy.production", params: { repo: "acme/payments-api", env: "production", sha: "8d93f71" }, }); deploy(decided.params);decided = outis.requests.assert_authorized( request.id, action="deploy.production", params={"repo": "acme/payments-api", "env": "production", "sha": "8d93f71"}, ) deploy(decided.params)decided, err := client.Requests.AssertAuthorized(ctx, req.ID, outis.Operation{ Action: "deploy.production", Params: map[string]string{"repo": "acme/payments-api", "env": "production", "sha": "8d93f71"}, }) if err != nil { return err } deploy(decided.Params)outcomeisnullwhile the request is live and one ofauthorized,denied,expiredorabortedonce it isn’t. Act onauthorizedonly, use theparamsfrom the answer, and check the hash before you run anything. The SDKs’assertAuthorized(assert_authorizedin Python) does both checks in one read. Operation hash covers the hash itself.
Where next
Section titled “Where next”- Receive callbacks instead of polling.
- Design the panel so an operator can tell the right deploy from the wrong one.
- How approval works for what quorum, modes and windows mean.