Skip to content

Compare changes

Choose two branches to see what one has that the other does not, then open a pull request for it.

Open a pull request

1 commit

50 files+8997−80670/50 viewed
+6−6
10241024 "Who the access token acts as, and the workspaces it can work in. `kind` is `user` for a person's token, `workspace` for a token that belongs to a workspace, and `agent` for the token a g1t agent works with."
10251025 }
10261026 Op::CreateWorkspace => {
1027− "Create a workspace. A workspace owns repositories and is the first part of their address: g1t.sh/{workspace}/{repo}. The whoami tool lists the ones you already belong to."
1027+ "Create a workspace. A workspace owns repositories and is the first part of their address: g1t.sh/{workspace}/{repo}. The whoami tool lists the ones you already belong to. A new workspace is free, and each person can own one free workspace: if you already own one (or several, from before), this is refused with `payment_required` (402) until each workspace you own is on the g1t plan or deleted. Workspaces with the plan, an enterprise's terms or a full discount do not count."
10281028 }
10291029 Op::ListEmails => {
10301030 "Your email addresses: each one's `email`, whether it is `verified` (confirmed), `primary` or the `backup`, and when it was added and confirmed. Also whether you keep your address private (`private_email`), your `noreply` address, and `commit_email`, the address on commits g1t makes for you. People only: an agent's or a workspace's token cannot read or change addresses."
10511051 "The invites made for a workspace, newest first, with each pending one's `code`. Owners only."
10521052 }
10531053 Op::InviteMember => {
1054− "Invite an email address into a workspace. It always makes an invite bound to that address and emails it the link, so the answer never says whether the address has a g1t account. Without one, accepting makes the account and joins the workspace in one step, and uses one of the workspace's granted invites, or else one of yours. With one, it costs nothing, and they join when they accept. To add someone by username at once, use the workspace's People page. Owners only."
1054+ "Invite an email address into a workspace. It always makes an invite bound to that address and emails it the link, so the answer never says whether the address has a g1t account. Without one, accepting makes the account and joins the workspace in one step, and uses one of the workspace's granted invites, or else one of yours. With one, it costs nothing, and they join when they accept. To add someone by username at once, use the workspace's People page. Owners only. A free workspace cannot invite anyone: this is refused with `payment_required` (402) until it starts the g1t plan, and an invite sent before cannot be accepted until then."
10551055 }
10561056 Op::RevokeWorkspaceInvite => "Revoke a workspace's pending invite. Owners only.",
10571057 Op::DeleteWorkspace => {
13411341 "Who has access to a repository: the workspace's `base_permission`, and `people`, everyone with a role on it other than through it being public. Each person has their effective `role` (read, triage, write, maintain or admin), its `source` (`owner` of the workspace, the workspace's `base` permission, or a `direct` role on this repository), their `direct` role if they have one, and their `workspace_role` (`owner`, `member`, or null for an outside collaborator). Pending `invitations` are listed for those with the Admin role, and empty for anyone else. `viewer_role` is your own role, and `can_manage` whether you may change who has access. Needs the Write role or higher. People only."
13421342 }
13431343 Op::AddCollaborator => {
1344− "Give someone a role on a repository, by username or email address. A member of its workspace gets the role at once (`result` is `granted`, with the `collaborator`). Anyone else becomes an outside collaborator once they accept an invitation, which is emailed to them and waits 7 days (`result` is `invited`, with the `invitation`); an address with no g1t account is sent an invite that makes the account and accepts in one step. The role is read, triage, write, maintain or admin. Needs the Admin role on the repository, signed in as a person with a confirmed email address; agents' and workspaces' tokens are refused."
1344+ "Give someone a role on a repository, by username or email address. A member of its workspace gets the role at once (`result` is `granted`, with the `collaborator`). Anyone else becomes an outside collaborator once they accept an invitation, which is emailed to them and waits 7 days (`result` is `invited`, with the `invitation`); an address with no g1t account is sent an invite that makes the account and accepts in one step. The role is read, triage, write, maintain or admin. Needs the Admin role on the repository, signed in as a person with a confirmed email address; agents' and workspaces' tokens are refused. A free workspace can give its members a role, but cannot invite anyone from outside it: that is refused with `payment_required` (402) until the workspace starts the g1t plan."
13451345 }
13461346 Op::UpdateCollaborator => {
13471347 "Change the role someone was given on a repository directly, or the role of their pending invitation. A role from ownership or the workspace's base permission is not changed here: an owner always has Admin, and a member never has less than the base permission. Needs the Admin role. People only."
13621362 "The invitations to repositories waiting for you to answer, sent to your username or to one of your confirmed email addresses, newest first. Accept or decline each by its `id`. People only; an agent's or a workspace's token gets an empty list."
13631363 }
13641364 Op::AcceptRepoInvitation => {
1365− "Accept an invitation to a repository sent to you. You get its role on that repository at once, as an outside collaborator unless you belong to its workspace. Refused when the workspace asks something of everyone with access that your account does not meet, such as two-factor authentication. People only."
1365+ "Accept an invitation to a repository sent to you. You get its role on that repository at once, as an outside collaborator unless you belong to its workspace. Refused when the workspace asks something of everyone with access that your account does not meet, such as two-factor authentication, and with `payment_required` (402) while the workspace is free: it can add no one until it starts the g1t plan, and the invitation waits until then. People only."
13661366 }
13671367 Op::DeclineRepoInvitation => {
13681368 "Decline an invitation to a repository sent to you. Whoever sent it can invite you again. People only."
14911491 "Start buying AI credit. Returns `url`, a payment page to open in a browser and pay by card; it comes back to the workspace's billing page. `amount_cents` is the credit, in whole dollars from $10 (1000) to $1,000 (100000); any card fee is added on top. The credit is added once the payment goes through. Owners only, as a person: signed in or with a personal access token. A workspace's own token and g1t's agents never buy credit."
14921492 }
14931493 Op::ListInvoices => {
1494− "A workspace's invoices, newest first. `invoices` is every invoice billed to it (the plan, activations, AI credit and usage), each with its `status`, `total_cents`, `currency` and links to view it and its PDF. `usage_invoices` are g1t's itemised invoices for usage, one when each month closes and one each time the card is charged near the limit, with their `lines` in millionths of a dollar. `upcoming` is what the next invoice comes to so far. `unavailable` says why `invoices` could not be read just now, when it could not. Members of the workspace only."
1494+ "A workspace's invoices, newest first. `invoices` is every invoice billed to it (the plan, activations, AI credit and usage), each with its `status`, `total_cents`, `currency` and links to view it and its PDF. `usage_invoices` are g1t's itemised invoices for usage, one when each month closes and one each time the card is charged near the limit, with their `lines` in millionths of a dollar; `amount_micros` is the usage, and the card processing fee (`fee_micros`) and tax (`tax_micros`) are on top. Prices exclude tax: Stripe adds it where it applies. `upcoming` is what the next invoice comes to so far. `unavailable` says why `invoices` could not be read just now, when it could not. Members of the workspace only."
14951495 }
14961496 Op::GetBillingDetails => {
1497− "Who a workspace's invoices are made out to: the billing `email`, `name`, `address`, tax ID (`tax_id_type`, `tax_id`), `po_number` and the invoices' `language`, with the default `payment_method` as far as it is safe to show (its kind, brand, last four digits and expiry). `customer` is false until the workspace has been set up to pay. Members of the workspace only."
1497+ "Who a workspace's invoices are made out to: the billing `email`, `name`, `address`, tax ID (`tax_id_type`, `tax_id`), `po_number` and the invoices' `language`, with the default `payment_method` as far as it is safe to show (its kind, brand, last four digits and expiry). `customer` is false until the workspace has been set up to pay. Tax is worked out from the address: `tax_location` says whether it is enough for that (a country, and in the US a ZIP code), `tax_address_needed_at` is set while g1t is holding a charge for want of one, `tax_id_status` is Stripe's check of the tax ID (`pending`, `verified`, `unverified` or `unavailable`), and `tax_exempt` is `none`, `exempt` or `reverse`. Members of the workspace only."
14981498 }
14991499 Op::ListUserTeams => {
15001500 "The teams someone is in within a workspace, as list_teams describes them, leaving out secret teams you cannot see. Members of the workspace only."
+8003−7976
11 {
2− "device_code": {
3− "request": {
4− "client_name": "Claude Code"
5− },
6− "response": {
7− "device_code": "Gm3k…",
8− "user_code": "WDJB-MJHT",
9− "verification_uri": "https://g1t.sh/device",
10− "verification_uri_complete": "https://g1t.sh/device?code=WDJB-MJHT",
11− "expires_in": 900,
12− "interval": 5
13− }
14− },
15− "device_token": {
16− "request": {
17− "device_code": "Gm3k…"
18− },
19− "response": {
20− "status": "approved",
21− "token": "g1t_…",
22− "username": "syntaqx",
23− "verified": true
24− }
25− },
26− "whoami": {
27− "response": {
28− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
29− "username": "syntaqx",
30− "kind": "user",
31− "verified": true,
32− "workspaces": [
33− {
34− "slug": "acme",
35− "role": "member",
36− "base_permission": "write"
37− },
38− {
39− "slug": "flagon-io",
40− "role": "owner",
41− "base_permission": "write"
42− }
43− ],
44− "token": {
45− "token_id": "tok_01kkntd3p2v8x6ym5r0c1q7a9e",
46− "scopes": [
47− "repo:read",
48− "issues:read",
49− "issues:write",
50− "pull_requests:read",
51− "pull_requests:write"
52− ]
53− }
54− },
55− "notes": "`token` is what the access token you called with may do: its `scopes` (left out for full access) and `legacy` when it was made before tokens had scopes. A token reaches every workspace and repository whoever it acts as can; its scopes say what it may do there. See [Scopes](/guides/authentication/#scopes). `kind` is `user`, `workspace` for a [workspace access token](/guides/workspaces/#workspace-access-tokens), or `agent` for the token a g1t agent works with. For a workspace token, `username` is the workspace's slug and `workspaces` holds only that workspace. Each workspace carries its `base_permission`: what a member gets on each of its repositories (owners have Admin). Roles given on single repositories are in `grants`, each with `repo_id`, `workspace` and `role`; it is left out when there are none. See [Access and roles](/guides/access-and-roles/)."
56− },
57− "create_workspace": {
58− "request": {
59− "slug": "acme-labs",
60− "name": "Acme Labs"
61− },
62− "response": {
63− "id": "wsp_01m43teqa9em6bje0bhvdj4jkb",
64− "slug": "acme-labs",
65− "name": "Acme Labs",
66− "description": null,
67− "created_at": "2026-10-04T16:02:51.337Z",
68− "member_count": 1,
69− "base_permission": "write",
70− "team_creation": "members"
71− },
72− "notes": "`base_permission` is what every member gets on each of its repositories: `write` until an owner changes it with `PATCH /workspaces/{workspace}` or `PUT /workspaces/{workspace}/base_permission`. See [Access and roles](/guides/access-and-roles/). `team_creation` is who may create its teams: `members` (any member) until an owner sets `owners` with `PATCH /workspaces/{workspace}`."
73− },
74− "get_workspace": {
75− "params": {
76− "workspace": "acme-labs"
77− },
78− "response": {
79− "id": "wsp_01m43teqa9em6bje0bhvdj4jkb",
80− "slug": "acme-labs",
81− "name": "Acme Labs",
82− "description": "Rockets, and the software that flies them.",
83− "created_at": "2026-10-04T16:02:51.337Z",
84− "member_count": 3,
85− "base_permission": "write",
86− "team_creation": "members"
87− },
88− "notes": "`team_creation` is who may create its teams: `members` (any member, the default) or `owners`. Change it, and the rest, with [`PATCH /workspaces/{workspace}`](/reference/api/workspaces/update-workspace/). `404` for anyone who is not a member. See [Workspaces](/guides/workspaces/)."
89− },
90− "update_workspace": {
91− "params": {
92− "workspace": "acme-labs"
93− },
94− "request": {
95− "name": "Acme Labs",
96− "description": "Rockets, and the software that flies them.",
97− "team_creation": "owners"
98− },
99− "response": {
100− "id": "wsp_01m43teqa9em6bje0bhvdj4jkb",
101− "slug": "acme-labs",
102− "name": "Acme Labs",
103− "description": "Rockets, and the software that flies them.",
104− "created_at": "2026-10-04T16:02:51.337Z",
105− "member_count": 3,
106− "base_permission": "write",
107− "team_creation": "owners"
108− },
109− "notes": "Only the fields given change. `name` is the display name; the slug, the first part of the workspace's addresses, stays as it is. `base_permission` needs the `access:admin` scope as well as `workspace:admin`; [`set_base_permission`](/reference/api/access/set-base-permission/) sets it alone. `team_creation` is `members` (any member may create a team, the default) or `owners`; teams already made stay. Refused with `403` for anyone but an owner signed in as a person. Recorded in the [audit log](/guides/audit-log/). See [Workspaces](/guides/workspaces/)."
110− },
111− "delete_workspace": {
112− "request": {
113− "confirm": "acme-labs"
114− },
115− "response": true,
116− "notes": "Refused with `402` while billing cannot settle it, with a message that says what to do, and with `403` for anyone but an owner signed in as a person, or for a protected workspace. Its repositories, projects and apps go with it; g1t's support can restore it for 30 days. See [Delete a workspace](/guides/workspaces/#delete-a-workspace)."
117− },
118− "list_emails": {
119− "response": {
120− "emails": [
121− {
122− "email": "ada@example.com",
123− "verified": true,
124− "primary": true,
125− "backup": false,
126− "created_at": "2026-09-01T10:00:00.000Z",
127− "verified_at": "2026-09-01T10:02:11.000Z"
128− },
129− {
130− "email": "ada@acme.com",
131− "verified": true,
132− "primary": false,
133− "backup": true,
134− "created_at": "2026-10-02T09:30:00.000Z",
135− "verified_at": "2026-10-02T09:31:40.000Z"
136− },
137− {
138− "email": "ada.l@example.org",
139− "verified": false,
140− "primary": false,
141− "backup": false,
142− "created_at": "2026-10-05T14:12:03.000Z",
143− "verified_at": null
144− }
145− ],
146− "private_email": true,
147− "block_private_pushes": false,
148− "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
149− "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
150− "limit": 10
151− },
152− "notes": "Your primary address comes first, then confirmed addresses, then unconfirmed ones. Any confirmed address signs you in, can reset your password and attributes commits to you. See [Email addresses](/guides/authentication/#email-addresses)."
153− },
154− "add_email": {
155− "request": {
156− "email": "ada.l@example.org",
157− "password": "…"
158− },
159− "response": {
160− "emails": [
161− {
162− "email": "ada@example.com",
163− "verified": true,
164− "primary": true,
165− "backup": false,
166− "created_at": "2026-09-01T10:00:00.000Z",
167− "verified_at": "2026-09-01T10:02:11.000Z"
168− },
169− {
170− "email": "ada@acme.com",
171− "verified": true,
172− "primary": false,
173− "backup": true,
174− "created_at": "2026-10-02T09:30:00.000Z",
175− "verified_at": "2026-10-02T09:31:40.000Z"
176− },
177− {
178− "email": "ada.l@example.org",
179− "verified": false,
180− "primary": false,
181− "backup": false,
182− "created_at": "2026-10-05T14:12:03.000Z",
183− "verified_at": null
184− }
185− ],
186− "private_email": true,
187− "block_private_pushes": false,
188− "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
189− "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
190− "limit": 10
191− },
192− "notes": "Answers `403` with code `reauth_required` when `password` is missing or wrong, and `409` when another account has confirmed the address. The new address stays unconfirmed until its link is followed."
193− },
194− "remove_email": {
195− "request": {
196− "password": "…"
197− },
198− "response": {
199− "emails": [
200− {
201− "email": "ada@example.com",
202− "verified": true,
203− "primary": true,
204− "backup": false,
205− "created_at": "2026-09-01T10:00:00.000Z",
206− "verified_at": "2026-09-01T10:02:11.000Z"
207− },
208− {
209− "email": "ada@acme.com",
210− "verified": true,
211− "primary": false,
212− "backup": true,
213− "created_at": "2026-10-02T09:30:00.000Z",
214− "verified_at": "2026-10-02T09:31:40.000Z"
215− },
216− {
217− "email": "ada.l@example.org",
218− "verified": false,
219− "primary": false,
220− "backup": false,
221− "created_at": "2026-10-05T14:12:03.000Z",
222− "verified_at": null
223− }
224− ],
225− "private_email": true,
226− "block_private_pushes": false,
227− "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
228− "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
229− "limit": 10
230− },
231− "notes": "Give the address in the path, URL-encoded: `DELETE /user/emails/ada.l%40example.org`. Answers `409` for your primary address or your last confirmed one."
232− },
233− "update_email_settings": {
234− "request": {
235− "primary": "ada@acme.com",
236− "password": "…"
237− },
238− "response": {
239− "emails": [
240− {
241− "email": "ada@example.com",
242− "verified": true,
243− "primary": true,
244− "backup": false,
245− "created_at": "2026-09-01T10:00:00.000Z",
246− "verified_at": "2026-09-01T10:02:11.000Z"
247− },
248− {
249− "email": "ada@acme.com",
250− "verified": true,
251− "primary": false,
252− "backup": true,
253− "created_at": "2026-10-02T09:30:00.000Z",
254− "verified_at": "2026-10-02T09:31:40.000Z"
255− },
256− {
257− "email": "ada.l@example.org",
258− "verified": false,
259− "primary": false,
260− "backup": false,
261− "created_at": "2026-10-05T14:12:03.000Z",
262− "verified_at": null
263− }
264− ],
265− "private_email": true,
266− "block_private_pushes": false,
267− "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
268− "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
269− "limit": 10
270− },
271− "notes": "Only the fields given change. `primary` and `backup` need `password`; `private_email` and `block_private_pushes` do not."
272− },
273− "list_invites": {
274− "response": {
275− "mode": "invite",
276− "allowance": {
277− "limit": 5,
278− "used": 2,
279− "remaining": 3
280− },
281− "workspaces": [
282− {
283− "slug": "acme-labs",
284− "allowance": {
285− "limit": 20,
286− "used": 4,
287− "remaining": 16
288− }
289− }
290− ],
291− "invites": [
292− {
293− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
294− "code": "g1t-k7m2-q9xd-4hpw-…",
295− "hint": "g1t-k7m2",
296− "email": "ada@example.com",
297− "kind": "account",
298− "workspace": null,
299− "status": "pending",
300− "charged_to": "user",
301− "invited_by": "syntaqx",
302− "redeemed_by": null,
303− "created_at": "2026-10-05T17:00:00.000Z",
304− "expires_at": "2026-11-04T17:00:00.000Z",
305− "redeemed_at": null,
306− "revoked_at": null
307− },
308− {
309− "id": "inv_01kp1v3c4d5e6f7g8h9j0k1m2n",
310− "code": null,
311− "hint": "g1t-p3rt",
312− "email": null,
313− "kind": "account",
314− "workspace": null,
315− "status": "redeemed",
316− "charged_to": "user",
317− "invited_by": "syntaqx",
318− "redeemed_by": "grace",
319− "created_at": "2026-10-02T09:12:40.000Z",
320− "expires_at": "2026-11-01T09:12:40.000Z",
321− "redeemed_at": "2026-10-02T11:30:05.000Z",
322− "revoked_at": null
323− }
324− ]
325− },
326− "notes": "`allowance.limit` and `allowance.remaining` are null when you have no limit. A revoked or expired invite that was never used is not counted. Ask for more at hey@flagon.io with the subject `[g1t Invites]`. See [Invites](/guides/authentication/#invites)."
327− },
328− "create_invite": {
329− "request": {
330− "email": "ada@example.com"
331− },
332− "response": {
333− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
334− "code": "g1t-k7m2-q9xd-4hpw-…",
335− "hint": "g1t-k7m2",
336− "email": "ada@example.com",
337− "kind": "account",
338− "workspace": null,
339− "status": "pending",
340− "charged_to": "user",
341− "invited_by": "syntaqx",
342− "redeemed_by": null,
343− "created_at": "2026-10-05T17:00:00.000Z",
344− "expires_at": "2026-11-04T17:00:00.000Z",
345− "redeemed_at": null,
346− "revoked_at": null
347− },
348− "notes": "Refused with `402` (`limit`) when you have no invites left, with `409` when you already have a pending invite for that address or it already has a g1t account, and with `403` for an agent's or a workspace's token. The code is returned in full; send people the link `https://g1t.sh/invite/<code>`."
349− },
350− "revoke_invite": {
351− "response": {
352− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
353− "code": null,
354− "hint": "g1t-k7m2",
355− "email": "ada@example.com",
356− "kind": "account",
357− "workspace": null,
358− "status": "revoked",
359− "charged_to": "user",
360− "invited_by": "syntaqx",
361− "redeemed_by": null,
362− "created_at": "2026-10-05T17:00:00.000Z",
363− "expires_at": "2026-11-04T17:00:00.000Z",
364− "redeemed_at": null,
365− "revoked_at": "2026-10-06T08:00:00.000Z"
366− }
367− },
368− "list_workspace_invites": {
369− "response": [
370− {
371− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
372− "code": "g1t-k7m2-q9xd-4hpw-…",
373− "hint": "g1t-k7m2",
374− "email": "ada@example.com",
375− "kind": "account",
376− "workspace": "acme-labs",
377− "status": "pending",
378− "charged_to": "workspace",
379− "invited_by": "syntaqx",
380− "redeemed_by": null,
381− "created_at": "2026-10-05T17:00:00.000Z",
382− "expires_at": "2026-11-04T17:00:00.000Z",
383− "redeemed_at": null,
384− "revoked_at": null
385− },
386− {
387− "id": "inv_01kp1z9y8x7w6v5t4s3r2q1p0n",
388− "code": "g1t-k7m2-q9xd-4hpw-…",
389− "hint": "g1t-w2vb",
390− "email": "linus@example.com",
391− "kind": "workspace",
392− "workspace": "acme-labs",
393− "status": "pending",
394− "charged_to": "none",
395− "invited_by": "syntaqx",
396− "redeemed_by": null,
397− "created_at": "2026-10-05T17:00:00.000Z",
398− "expires_at": "2026-11-04T17:00:00.000Z",
399− "redeemed_at": null,
400− "revoked_at": null
401− }
402− ]
403− },
404− "invite_member": {
405− "request": {
406− "email": "ada@example.com"
407− },
408− "response": {
409− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
410− "code": "g1t-k7m2-q9xd-4hpw-…",
411− "hint": "g1t-k7m2",
412− "email": "ada@example.com",
413− "kind": "account",
414− "workspace": "acme-labs",
415− "status": "pending",
416− "charged_to": "workspace",
417− "invited_by": "syntaqx",
418− "redeemed_by": null,
419− "created_at": "2026-10-05T17:00:00.000Z",
420− "expires_at": "2026-11-04T17:00:00.000Z",
421− "redeemed_at": null,
422− "revoked_at": null
423− },
424− "notes": "`kind` is `workspace` when the address already has a g1t account (`charged_to` is then `none`), and `account` when accepting makes one. Both answers look alike to the caller on purpose: the invite is emailed either way."
425− },
426− "revoke_workspace_invite": {
427− "response": {
428− "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
429− "code": null,
430− "hint": "g1t-k7m2",
431− "email": "ada@example.com",
432− "kind": "account",
433− "workspace": "acme-labs",
434− "status": "revoked",
435− "charged_to": "workspace",
436− "invited_by": "syntaqx",
437− "redeemed_by": null,
438− "created_at": "2026-10-05T17:00:00.000Z",
439− "expires_at": "2026-11-04T17:00:00.000Z",
440− "redeemed_at": null,
441− "revoked_at": "2026-10-06T08:00:00.000Z"
442− }
443− },
444− "list_repos": {
445− "query": {
446− "q": "hello"
447− },
448− "response": [
449− {
450− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
451− "namespace": "flagon-io",
452− "name": "hello",
453− "description": "A tiny service that says hello.",
454− "is_private": false,
455− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
456− "default_branch": "main",
457− "fork_of": null,
458− "protected": true,
459− "created_at": "2026-09-28T14:11:52.640Z",
460− "website": "https://hello.g1t.page",
461− "archived_at": null
462− }
463− ],
464− "notes": "Returns at most 50 repositories, newest first. Forks made for pull requests are left out."
465− },
466− "create_repo": {
467− "request": {
468− "workspace": "flagon-io",
469− "name": "hello-cli",
470− "description": "Command-line client for hello.",
471− "private": false
472− },
473− "response": {
474− "id": "rep_01m43tk1jhehztx23drs87f5fc",
475− "namespace": "flagon-io",
476− "name": "hello-cli",
477− "description": "Command-line client for hello.",
478− "is_private": false,
479− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
480− "default_branch": "main",
481− "fork_of": null,
482− "protected": false,
483− "created_at": "2026-10-04T16:05:12.913Z",
484− "website": "https://hello.g1t.page",
485− "archived_at": null
486− },
487− "notes": "`owner_id` is the id of the person who created the repository. With `import_url`, `default_branch` is the default branch of the repository copied."
488− },
489− "get_repo": {
490− "response": {
491− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
492− "namespace": "flagon-io",
493− "name": "hello",
494− "description": "A tiny service that says hello.",
495− "is_private": false,
496− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
497− "default_branch": "main",
498− "fork_of": null,
499− "protected": true,
500− "created_at": "2026-09-28T14:11:52.640Z",
501− "website": "https://hello.g1t.page",
502− "archived_at": null
503− }
504− },
505− "update_repo": {
506− "request": {
507− "description": "Says hello, politely.",
508− "website": "hello.g1t.page",
509− "default_branch": "trunk",
510− "protected": true
511− },
512− "response": {
513− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
514− "namespace": "flagon-io",
515− "name": "hello",
516− "description": "Says hello, politely.",
517− "is_private": false,
518− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
519− "default_branch": "trunk",
520− "fork_of": null,
521− "protected": true,
522− "created_at": "2026-09-28T14:11:52.640Z",
523− "topics": [
524− "http",
525− "example"
526− ],
527− "website": "https://hello.g1t.page",
528− "archived_at": null
529− },
530− "notes": "Only the fields given change. `website` gets `https://` when no scheme is given; an empty string clears it. `default_branch` must name a branch that exists (`422` otherwise); it is changed after the other fields. `description`, `website`, `topics` and `protected` need the Maintain role or higher, and `private` and `default_branch` the Admin role (`403` otherwise, saying which role). Changing `private` here needs no confirmation; `POST /repos/{owner}/{name}/visibility` asks for one. Making it private is refused with `402` when a free workspace's private storage has no room for it. See [Managing a repository](/guides/managing-repositories/) and [Access and roles](/guides/access-and-roles/)."
531− },
532− "transfer_repo": {
533− "request": {
534− "to": "flagon-io"
535− },
536− "response": {
537− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
538− "namespace": "flagon-io",
539− "name": "hello",
540− "description": "A tiny service that says hello.",
541− "is_private": false,
542− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
543− "default_branch": "main",
544− "fork_of": null,
545− "protected": true,
546− "created_at": "2026-09-28T14:11:52.640Z",
547− "website": "https://hello.g1t.page",
548− "archived_at": null
549− },
550− "notes": "The repository at its new address. Refused with `409` when the destination already has a repository of that name, `403` unless you own both workspaces, and `402` when a free destination has no room for a private repository. The old address redirects. See [Transferring a repository](/guides/transferring-repositories/)."
551− },
552− "rename_repo": {
553− "request": {
554− "name": "greeter"
555− },
556− "response": {
557− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
558− "namespace": "flagon-io",
559− "name": "greeter",
560− "description": "A tiny service that says hello.",
561− "is_private": false,
562− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
563− "default_branch": "main",
564− "fork_of": null,
565− "protected": true,
566− "created_at": "2026-09-28T14:11:52.640Z",
567− "topics": [
568− "http",
569− "example"
570− ],
571− "website": "https://hello.g1t.page",
572− "archived_at": null
573− },
574− "notes": "The repository under its new name. Needs the Admin role (`403` otherwise). Refused with `409` when the workspace already has a repository of that name, a recently deleted one included, and with `422` when the name is not valid. The old address redirects. See [Rename a repository](/guides/managing-repositories/#rename-a-repository)."
575− },
576− "rename_branch": {
577− "params": {
578− "owner": "flagon-io",
579− "name": "hello",
580− "branch": "feature/login"
581− },
582− "request": {
583− "new_name": "feature/sign-in"
584− },
585− "response": {
586− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
587− "namespace": "flagon-io",
588− "name": "hello",
589− "description": "A tiny service that says hello.",
590− "is_private": false,
591− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
592− "default_branch": "main",
593− "fork_of": null,
594− "protected": true,
595− "created_at": "2026-09-28T14:11:52.640Z",
596− "topics": [
597− "http",
598− "example"
599− ],
600− "website": "https://hello.g1t.page",
601− "archived_at": null
602− },
603− "notes": "The repository after the rename; renaming the default branch changes `default_branch`. Send a branch name with slashes URL-encoded, as one path segment. Refused with `404` when there is no such branch, `409` when a branch named `new_name` exists, `422` when `new_name` is not a valid branch name, and `403` without the Write role, or without the Admin role for the default branch. See [Rename a branch](/guides/managing-repositories/#rename-a-branch)."
604− },
605− "set_repo_visibility": {
606− "request": {
607− "private": true,
608− "confirm": "flagon-io/hello"
609− },
610− "response": {
611− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
612− "namespace": "flagon-io",
613− "name": "hello",
614− "description": "A tiny service that says hello.",
615− "is_private": true,
616− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
617− "default_branch": "main",
618− "fork_of": null,
619− "protected": true,
620− "created_at": "2026-09-28T14:11:52.640Z",
621− "topics": [
622− "http",
623− "example"
624− ],
625− "website": "https://hello.g1t.page",
626− "archived_at": null
627− },
628− "notes": "Needs the Admin role (`403` otherwise). Refused with `422` when `confirm` is not the repository's full name, and with `402` when a free workspace's private storage has no room for it. See [Change who can see a repository](/guides/managing-repositories/#change-who-can-see-a-repository)."
629− },
630− "archive_repo": {
631− "response": {
632− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
633− "namespace": "flagon-io",
634− "name": "hello",
635− "description": "A tiny service that says hello.",
636− "is_private": false,
637− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
638− "default_branch": "main",
639− "fork_of": null,
640− "protected": true,
641− "created_at": "2026-09-28T14:11:52.640Z",
642− "topics": [
643− "http",
644− "example"
645− ],
646− "website": "https://hello.g1t.page",
647− "archived_at": "2026-10-05T09:30:00.000Z"
648− },
649− "notes": "The repository, with `archived_at` set. Needs the Admin role (`403` otherwise). See [Archive a repository](/guides/managing-repositories/#archive-a-repository)."
650− },
651− "unarchive_repo": {
652− "response": {
653− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
654− "namespace": "flagon-io",
655− "name": "hello",
656− "description": "A tiny service that says hello.",
657− "is_private": false,
658− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
659− "default_branch": "main",
660− "fork_of": null,
661− "protected": true,
662− "created_at": "2026-09-28T14:11:52.640Z",
663− "topics": [
664− "http",
665− "example"
666− ],
667− "website": "https://hello.g1t.page",
668− "archived_at": null
669− },
670− "notes": "The repository, with `archived_at` null. Needs the Admin role (`403` otherwise)."
671− },
672− "delete_repo": {
673− "request": {
674− "confirm": "flagon-io/hello"
675− },
676− "response": {
677− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
678− "namespace": "flagon-io",
679− "name": "hello",
680− "description": "A tiny service that says hello.",
681− "is_private": false,
682− "deleted_at": "2026-10-05T09:30:00.000Z",
683− "deleted_by": "syntaqx",
684− "purge_after": "2026-11-04T09:30:00.000Z"
685− },
686− "notes": "The deleted repository and when it will be purged, 30 days on. Owners of the workspace only (`403`), whatever their role on the repository. Refused with `422` when `confirm` is not its full name. Its name stays taken until it is purged. See [Delete a repository](/guides/managing-repositories/#delete-a-repository)."
687− },
688− "list_deleted_repos": {
689− "params": {
690− "workspace": "flagon-io"
691− },
692− "response": [
693− {
694− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
695− "namespace": "flagon-io",
696− "name": "hello",
697− "description": "A tiny service that says hello.",
698− "is_private": false,
699− "deleted_at": "2026-10-05T09:30:00.000Z",
700− "deleted_by": "syntaqx",
701− "purge_after": "2026-11-04T09:30:00.000Z"
702− }
703− ],
704− "notes": "Newest first. Empty for anyone who is not an owner of the workspace."
705− },
706− "restore_repo": {
707− "response": {
708− "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
709− "namespace": "flagon-io",
710− "name": "hello",
711− "description": "A tiny service that says hello.",
712− "is_private": false,
713− "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
714− "default_branch": "main",
715− "fork_of": null,
716− "protected": true,
717− "created_at": "2026-09-28T14:11:52.640Z",
718− "topics": [
719− "http",
720− "example"
721− ],
722− "website": "https://hello.g1t.page",
723− "archived_at": null
724− },
725− "notes": "The repository, back at its address. Name it by the path it had. Owners only (`403`); `404` when no deleted repository had that path, or it has been purged. See [Restore a repository](/guides/managing-repositories/#restore-a-repository)."
726− },
727− "purge_repo": {
728− "request": {
729− "confirm": "flagon-io/hello"
730− },
731− "response": true,
732− "notes": "Permanent: it cannot be restored afterwards, and its name is free again. Only a deleted repository can be purged (`404` otherwise). Owners only (`403`); `422` when `confirm` is not its full name."
733− },
734− "get_repo_settings": {
735− "response": {
736− "auto_merge": false,
737− "required_checks": [
738− "CI"
739− ],
740− "require_up_to_date": false,
741− "required_approvals": 0,
742− "count_agent_approvals": true,
743− "allow_ignoring_checks": true,
744− "agent_review": true,
745− "max_revisions": 2,
746− "merge_queue": false,
747− "hold_low_confidence": true,
748− "require_code_owner_review": false,
749− "updated_by": null,
750− "updated_at": null
751− }
752− },
753− "update_repo_settings": {
754− "request": {
755− "required_checks": [
756− "CI",
757− "g1t / deploy"
758− ],
759− "required_approvals": 1,
760− "count_agent_approvals": false,
761− "merge_queue": true,
762− "require_code_owner_review": true
763− },
764− "response": {
765− "auto_merge": false,
766− "required_checks": [
767− "CI",
768− "g1t / deploy"
769− ],
770− "require_up_to_date": false,
771− "required_approvals": 1,
772− "count_agent_approvals": false,
773− "allow_ignoring_checks": true,
774− "agent_review": true,
775− "max_revisions": 2,
776− "merge_queue": true,
777− "hold_low_confidence": true,
778− "require_code_owner_review": true,
779− "updated_by": "syntaqx",
780− "updated_at": "2026-10-04T16:20:37.508Z"
781− },
782− "notes": "`required_checks` replaces the whole list: at most 20 names, each a workflow's name or another status's context, as [`list_check_names`](/reference/api/repositories/list-check-names/) gives them. A pull request merges only once each passes on its head; one nothing has reported holds it too. With the merge queue on, each must also pass on the queued state, so the workflows behind them need `merge_group` in their `on:`. `required_approvals` is at most 6 and `max_revisions` at most 5. See [what a repository can ask for](/guides/working-with-g1t/#what-a-repository-can-ask-for). `hold_low_confidence` is on unless turned off: see [confidence](/guides/working-with-g1t/#how-sure-the-agent-is). With `require_code_owner_review`, a pull request into the default branch merges only once the code owners of every file it changes have approved it, as many as each section of its CODEOWNERS file asks: see [Code owners](/guides/codeowners/)."
783− },
784− "list_check_names": {
785− "response": [
786− {
787− "name": "CI",
788− "events": [
789− "pull_request",
790− "merge_group",
791− "push"
792− ],
793− "last_seen": "2026-10-06T09:14:02.118Z"
794− },
795− {
796− "name": "g1t / deploy",
797− "events": [],
798− "last_seen": "2026-10-06T08:51:40.006Z"
799− }
800− ],
801− "notes": "The names reported on the repository's commits in the last 30 days, most recent first. A workflow reports a check named after it (`CI`), for each event it ran for; another tool, such as a deployment, reports its own name (`g1t / deploy`). Empty until something has reported on a commit: add a workflow in `.g1t/workflows` first."
802− },
803− "get_codeowners_errors": {
804− "params": {
805− "owner": "flagon-io",
806− "name": "hello"
807− },
808− "query": {
809− "ref": "main"
810− },
811− "response": {
812− "path": ".github/CODEOWNERS",
813− "ref": "main",
814− "size": 412,
815− "rules": 9,
816− "sections": [
817− "Docs"
818− ],
819− "errors": [
820− {
821− "line": 4,
822− "kind": "unknown_team",
823− "token": "@flagon-io/platform",
824− "message": "@flagon-io/platform is not a team of flagon-io."
825− },
826− {
827− "line": 7,
828− "kind": "negation",
829− "token": "!docs/internal/",
830− "message": "!docs/internal/ starts with !, and negation is not supported; this line is skipped. Give the path a later rule with no owners instead."
831− }
832− ]
833− },
834− "notes": "The file is the first of `.g1t/CODEOWNERS`, `.github/CODEOWNERS`, `CODEOWNERS`, `docs/CODEOWNERS` and `.gitlab/CODEOWNERS` found on `ref` (the default branch when left out); `path` is null when there is none, with no errors. Each error has its `line` (0 for the file as a whole), the `token` at fault, a `message`, and a `kind`:\n\n| `kind` | |\n| --- | --- |\n| `too_large` | The file is over 3 MB and was ignored. |\n| `negation` | A pattern starting with `!`; the line was skipped. |\n| `character_range` | A pattern with `[` or `]`; the line was skipped. |\n| `bad_pattern` | A pattern that names no path; the line was skipped. |\n| `bad_owner` | An owner that is not `@user`, `@workspace/team` or an email address. |\n| `bad_section` | A section header that could not be read. |\n| `unknown_user` | No account has that username. |\n| `unknown_team` | The workspace has no team of that slug. |\n| `unknown_email` | No account has confirmed that address. |\n| `no_write_access` | The person cannot write to the repository. |\n| `team_no_access` | The team has no write access to the repository. |\n\nSee [Code owners](/guides/codeowners/)."
835− },
836− "list_events": {
837− "query": {
838− "before": "evt_01m43t2a6c9e3g7j1m5q9t3x7b"
839− },
840− "response": [
841− {
842− "id": "evt_01m43smh3ve52vkcna207vqctf",
843− "type": "pull.opened",
844− "source": "work",
845− "time": "2026-10-01T18:20:02.117Z",
846− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
847− "actor": "usr_01kkntcg1eeb98j62xjm7eh09p",
848− "data": {
849− "pull_id": "pr_01m43smh3vexsr5pmp60qwv0vs",
850− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
851− "number": 14,
852− "issue": 12,
853− "agent": "claude-code"
854− }
855− },
856− {
857− "id": "evt_01m43shrzpf2vt5rxbb02z0xjt",
858− "type": "issue.opened",
859− "source": "work",
860− "time": "2026-10-01T18:04:11.482Z",
861− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
862− "actor": "usr_01kkntcg1eeb98j62xjm7eh09p",
863− "data": {
864− "issue_id": "iss_01m43shrzpfe49x74ga7sj1c6v",
865− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
866− "number": 12,
867− "title": "Greeting should name the caller"
868− }
869− }
870− ],
871− "notes": "Returns 50 events a page. To page back, send the `id` of the last event you have as `before`. `actor` is a user id, and `data` depends on `type`."
872− },
873− "list_issues": {
874− "query": {
875− "state": "open",
876− "label": "feature"
877− },
878− "response": [
879− {
880− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
881− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
882− "number": 12,
883− "title": "Greeting should name the caller",
884− "body": "Take a name from the first argument; fall back to world.",
885− "labels": [
886− "feature"
887− ],
888− "state": "open",
889− "reason": null,
890− "resolved_by": null,
891− "author": {
892− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
893− "username": "syntaqx",
894− "kind": "user",
895− "verified": false,
896− "workspaces": []
897− },
898− "requested_by": null,
899− "created_at": "2026-10-01T18:04:11.482Z",
900− "updated_at": "2026-10-01T18:04:11.482Z",
901− "closed_at": null,
902− "pull_count": 1,
903− "comment_count": 0,
904− "assignees": [],
905− "blocked_by": [],
906− "queued": false,
907− "agent": "claude-code",
908− "milestone": null
909− }
910− ],
911− "notes": "Returns at most 100 issues, newest first. `comment_count` counts comments, not events such as \"opened #14 for this\"."
912− },
913− "create_issue": {
914− "request": {
915− "title": "Greeting should name the caller",
916− "body": "Take a name from the first argument; fall back to world.",
917− "labels": [
918− "feature"
919− ]
920− },
921− "response": {
922− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
923− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
924− "number": 12,
925− "title": "Greeting should name the caller",
926− "body": "Take a name from the first argument; fall back to world.",
927− "labels": [
928− "feature"
929− ],
930− "state": "open",
931− "reason": null,
932− "resolved_by": null,
933− "author": {
934− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
935− "username": "syntaqx",
936− "kind": "user",
937− "verified": false,
938− "workspaces": []
939− },
940− "requested_by": null,
941− "created_at": "2026-10-01T18:04:11.482Z",
942− "updated_at": "2026-10-01T18:04:11.482Z",
943− "closed_at": null,
944− "pull_count": 0,
945− "comment_count": 0,
946− "assignees": [],
947− "blocked_by": [],
948− "queued": false,
949− "agent": null,
950− "milestone": null
951− },
952− "notes": "Labels are lowercased. A label not used before is created."
953− },
954− "get_issue": {
955− "response": {
956− "issue": {
957− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
958− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
959− "number": 12,
960− "title": "Greeting should name the caller",
961− "body": "Take a name from the first argument; fall back to world.",
962− "labels": [
963− "feature"
964− ],
965− "state": "closed",
966− "reason": "completed",
967− "resolved_by": 14,
968− "author": {
969− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
970− "username": "syntaqx",
971− "kind": "user",
972− "verified": false,
973− "workspaces": []
974− },
975− "requested_by": null,
976− "created_at": "2026-10-01T18:04:11.482Z",
977− "updated_at": "2026-10-01T18:52:17.093Z",
978− "closed_at": "2026-10-01T18:52:17.093Z",
979− "pull_count": 2,
980− "comment_count": 0,
981− "assignees": [],
982− "blocked_by": [],
983− "queued": false,
984− "agent": null,
985− "milestone": null
986− },
987− "pulls": [
988− {
989− "id": "pr_01m43sjq8tcz5rbm2a7k4d9e6w",
990− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
991− "number": 13,
992− "issue": 12,
993− "title": "Greeting should name the caller",
994− "body": null,
995− "agent": "claude-code",
996− "runtime": "external",
997− "status": "closed",
998− "fork": {
999− "namespace": "pulls",
1000− "name": "pr_01m43sjq8tcz5rbm2a7k4d9e6w"
1001− },
1002− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1003− "branch": null,
1004− "head_commit": null,
1005− "merge_base": null,
1006− "merged_by": null,
1007− "merged_at": null,
1008− "superseded_by": 14,
1009− "check_status": null,
1010− "files": [],
1011− "assignees": [],
1012− "reviewers": [],
1013− "labels": [],
1014− "milestone": null,
1015− "base": "main",
1016− "author": {
1017− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1018− "username": "syntaqx",
1019− "kind": "user",
1020− "verified": false,
1021− "workspaces": []
1022− },
1023− "requested_by": null,
1024− "created_at": "2026-10-01T18:20:02.117Z",
1025− "updated_at": "2026-10-01T18:20:02.117Z"
1026− },
1027− {
1028− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1029− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1030− "number": 14,
1031− "issue": 12,
1032− "title": "Greeting should name the caller",
1033− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1034− "agent": "claude-code",
1035− "runtime": "external",
1036− "status": "merged",
1037− "fork": {
1038− "namespace": "pulls",
1039− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1040− },
1041− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1042− "branch": null,
1043− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1044− "merge_base": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
1045− "merged_by": "syntaqx",
1046− "merged_at": "2026-10-01T18:52:17.093Z",
1047− "superseded_by": null,
1048− "check_status": "passed",
1049− "files": [
1050− {
1051− "path": "src/main.rs",
1052− "additions": 6,
1053− "deletions": 2
1054− }
1055− ],
1056− "assignees": [],
1057− "reviewers": [
1058− "ana"
1059− ],
1060− "labels": [],
1061− "milestone": null,
1062− "base": "main",
1063− "author": {
1064− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1065− "username": "syntaqx",
1066− "kind": "user",
1067− "verified": false,
1068− "workspaces": []
1069− },
1070− "requested_by": null,
1071− "created_at": "2026-10-01T18:20:02.117Z",
1072− "updated_at": "2026-10-01T18:52:17.093Z"
1073− }
1074− ],
1075− "comments": [
1076− {
1077− "id": "cmt_01m43sr2b7d5f0j6k3n8p1q4v9",
1078− "kind": "event",
1079− "author": {
1080− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1081− "username": "syntaqx",
1082− "kind": "user",
1083− "verified": false,
1084− "workspaces": []
1085− },
1086− "body": "opened #14 for this",
1087− "path": null,
1088− "line": null,
1089− "verdict": null,
1090− "created_at": "2026-10-01T18:20:02.141Z"
1091− }
1092− ]
1093− },
1094− "notes": "A closed issue says how it was closed: `reason` is `completed` or `not_planned`, and `resolved_by` is the number of the pull request whose merge closed it. Each pull request made for it is listed; one closed because another was merged has `superseded_by` set."
1095− },
1096− "update_issue": {
1097− "request": {
1098− "labels": [
1099− "feature",
1100− "good first issue"
1101− ],
1102− "assignees": [
1103− "syntaqx"
1104− ],
1105− "milestone": 3
1106− },
1107− "response": {
1108− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1109− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1110− "number": 12,
1111− "title": "Greeting should name the caller",
1112− "body": "Take a name from the first argument; fall back to world.",
1113− "labels": [
1114− "feature",
1115− "good first issue"
1116− ],
1117− "state": "open",
1118− "reason": null,
1119− "resolved_by": null,
1120− "author": {
1121− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1122− "username": "syntaqx",
1123− "kind": "user",
1124− "verified": false,
1125− "workspaces": []
1126− },
1127− "requested_by": null,
1128− "created_at": "2026-10-01T18:04:11.482Z",
1129− "updated_at": "2026-10-01T18:09:47.305Z",
1130− "closed_at": null,
1131− "pull_count": 0,
1132− "comment_count": 0,
1133− "assignees": [
1134− "syntaqx"
1135− ],
1136− "blocked_by": [],
1137− "queued": false,
1138− "agent": null,
1139− "milestone": {
1140− "number": 3,
1141− "title": "Launch"
1142− }
1143− }
1144− },
1145− "close_issue": {
1146− "request": {
1147− "reason": "not_planned"
1148− },
1149− "response": {
1150− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1151− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1152− "number": 12,
1153− "title": "Greeting should name the caller",
1154− "body": "Take a name from the first argument; fall back to world.",
1155− "labels": [
1156− "feature"
1157− ],
1158− "state": "closed",
1159− "reason": "not_planned",
1160− "resolved_by": null,
1161− "author": {
1162− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1163− "username": "syntaqx",
1164− "kind": "user",
1165− "verified": false,
1166− "workspaces": []
1167− },
1168− "requested_by": null,
1169− "created_at": "2026-10-01T18:04:11.482Z",
1170− "updated_at": "2026-10-01T19:30:00.214Z",
1171− "closed_at": "2026-10-01T19:30:00.214Z",
1172− "pull_count": 0,
1173− "comment_count": 0,
1174− "assignees": [],
1175− "blocked_by": [],
1176− "queued": false,
1177− "agent": null,
1178− "milestone": null
1179− }
1180− },
1181− "reopen_issue": {
1182− "response": {
1183− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1184− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1185− "number": 12,
1186− "title": "Greeting should name the caller",
1187− "body": "Take a name from the first argument; fall back to world.",
1188− "labels": [
1189− "feature"
1190− ],
1191− "state": "open",
1192− "reason": null,
1193− "resolved_by": null,
1194− "author": {
1195− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1196− "username": "syntaqx",
1197− "kind": "user",
1198− "verified": false,
1199− "workspaces": []
1200− },
1201− "requested_by": null,
1202− "created_at": "2026-10-01T18:04:11.482Z",
1203− "updated_at": "2026-10-01T19:41:52.830Z",
1204− "closed_at": null,
1205− "pull_count": 0,
1206− "comment_count": 0,
1207− "assignees": [],
1208− "blocked_by": [],
1209− "queued": false,
1210− "agent": null,
1211− "milestone": null
1212− }
1213− },
1214− "assign_issue": {
1215− "request": {
1216− "instructions": "Keep the change to src/main.rs."
1217− },
1218− "response": {
1219− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1220− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1221− "number": 14,
1222− "issue": 12,
1223− "title": "Greeting should name the caller",
1224− "body": null,
1225− "agent": "g1t",
1226− "runtime": "hosted",
1227− "status": "draft",
1228− "fork": {
1229− "namespace": "pulls",
1230− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1231− },
1232− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1233− "branch": null,
1234− "head_commit": null,
1235− "merge_base": null,
1236− "merged_by": null,
1237− "merged_at": null,
1238− "superseded_by": null,
1239− "check_status": null,
1240− "files": [],
1241− "assignees": [],
1242− "reviewers": [],
1243− "labels": [],
1244− "milestone": null,
1245− "base": "main",
1246− "author": {
1247− "id": "usr_g1t_agent",
1248− "username": "g1t",
1249− "kind": "agent",
1250− "verified": false,
1251− "workspaces": []
1252− },
1253− "requested_by": {
1254− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1255− "username": "syntaqx",
1256− "kind": "user",
1257− "verified": false,
1258− "workspaces": []
1259− },
1260− "created_at": "2026-10-01T18:20:02.117Z",
1261− "updated_at": "2026-10-01T18:20:02.117Z",
1262− "confidence": null
1263− },
1264− "notes": "The response is the pull request g1t opened, still a draft. g1t is its `author` and you are its `requested_by`: you may manage it as if you had opened it, and cannot approve it yourself. Follow it with [get a pull request](/reference/api/pull-requests/get-pull-request/): `lifecycle` says what the agent is doing."
1265− },
1266− "delegate": {
1267− "request": {
1268− "title": "Retry webhooks with exponential backoff",
1269− "body": "Deliveries that fail are dropped today. Retry them with exponential backoff, up to six times, then mark the delivery failed.\n\n## Definition of done\n\n- A delivery that fails is retried after 1, 2, 4, 8, 16 and 32 seconds.\n- After the sixth failure it is marked failed and shows on the webhook's page."
1270− },
1271− "response": {
1272− "issue": {
1273− "id": "iss_01m4a2c8v1t7k3q9x5n0r2w6yd",
1274− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1275− "number": 41,
1276− "title": "Retry webhooks with exponential backoff",
1277− "body": "Deliveries that fail are dropped today. Retry them with exponential backoff, up to six times, then mark the delivery failed.",
1278− "labels": [],
1279− "state": "open",
1280− "reason": null,
1281− "resolved_by": null,
1282− "author": {
1283− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1284− "username": "syntaqx",
1285− "kind": "user",
1286− "verified": false,
1287− "workspaces": []
1288− },
1289− "requested_by": null,
1290− "created_at": "2026-10-05T14:02:11.204Z",
1291− "updated_at": "2026-10-05T14:02:11.204Z",
1292− "closed_at": null,
1293− "pull_count": 1,
1294− "comment_count": 0,
1295− "assignees": [],
1296− "blocked_by": [],
1297− "queued": false,
1298− "agent": "g1t",
1299− "milestone": null
1300− },
1301− "pull": {
1302− "id": "pr_01m4a2c9b6e0h4m8q2t6x0a4d8",
1303− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1304− "number": 42,
1305− "issue": 41,
1306− "title": "Retry webhooks with exponential backoff",
1307− "body": null,
1308− "agent": "g1t",
1309− "runtime": "hosted",
1310− "status": "draft",
1311− "fork": {
1312− "namespace": "pulls",
1313− "name": "pr_01m4a2c9b6e0h4m8q2t6x0a4d8"
1314− },
1315− "fork_repo_id": "rep_01m4a2c9d2g6k0n4r8v2z6c0f4",
1316− "branch": null,
1317− "head_commit": null,
1318− "merge_base": null,
1319− "merged_by": null,
1320− "merged_at": null,
1321− "superseded_by": null,
1322− "check_status": null,
1323− "files": [],
1324− "assignees": [],
1325− "reviewers": [],
1326− "labels": [],
1327− "milestone": null,
1328− "base": "main",
1329− "author": {
1330− "id": "usr_g1t_agent",
1331− "username": "g1t",
1332− "kind": "agent",
1333− "verified": false,
1334− "workspaces": []
1335− },
1336− "requested_by": {
1337− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1338− "username": "syntaqx",
1339− "kind": "user",
1340− "verified": false,
1341− "workspaces": []
1342− },
1343− "created_at": "2026-10-05T14:02:12.880Z",
1344− "updated_at": "2026-10-05T14:02:12.880Z",
1345− "confidence": null
1346− },
1347− "agent": {
1348− "status": "started",
1349− "code": null,
1350− "message": null,
1351− "fix_url": null
1352− }
1353− },
1354− "notes": "The issue is opened whatever becomes of the agent. When the workspace's plan does not let it start, `pull` is null and `agent` says why and where to fix it, for example `{ \"status\": \"not_started\", \"code\": \"not_paid\", \"message\": \"Agents need a paid workspace. Start the $20 plan or try it with $5 of free usage after a card check: /acme/-/billing\", \"fix_url\": \"https://g1t.sh/acme/-/billing\" }`. With every agent slot busy, `status` is `queued` and it starts by itself when one frees up. See [putting an agent on something](/guides/working-with-g1t/#put-an-agent-on-it-in-one-step)."
1355− },
1356− "add_comment": {
1357− "request": {
1358− "body": "Should an empty name fall back to \"world\"?"
1359− },
1360− "response": {
1361− "id": "cmt_01m43sv4c8e2g6j0m4q8t2x6a1",
1362− "kind": "comment",
1363− "author": {
1364− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1365− "username": "syntaqx",
1366− "kind": "user",
1367− "verified": true,
1368− "workspaces": [
1369− {
1370− "slug": "flagon-io",
1371− "role": "owner"
1372− }
1373− ]
1374− },
1375− "body": "Should an empty name fall back to \"world\"?",
1376− "path": null,
1377− "line": null,
1378− "verdict": null,
1379− "created_at": "2026-10-01T18:12:30.551Z"
1380− }
1381− },
1382− "list_labels": {
1383− "response": [
1384− {
1385− "name": "bug",
1386− "color": "d73a4a",
1387− "description": "Something isn't working",
1388− "issues": 4,
1389− "pulls": 1
1390− },
1391− {
1392− "name": "dependencies",
1393− "color": "0366d6",
1394− "description": "Updates a dependency",
1395− "issues": 0,
1396− "pulls": 6
1397− },
1398− {
1399− "name": "good first issue",
1400− "color": "7057ff",
1401− "description": "Good for newcomers",
1402− "issues": 2,
1403− "pulls": 0
1404− }
1405− ],
1406− "notes": "By name. A new repository starts with the default labels; add_default_labels adds those an older one is missing."
1407− },
1408− "plan_work": {
1409− "request": {
1410− "brief": "Greet people by name, from the command line and the web page."
1411− },
1412− "response": {
1413− "plan_id": "pln_01m43s9c4e8g2j6m0q4t8x2b6d"
1414− }
1415− },
1416− "get_plan": {
1417− "params": {
1418− "plan": "pln_01m43s9c4e8g2j6m0q4t8x2b6d"
1419− },
1420− "response": {
1421− "id": "pln_01m43s9c4e8g2j6m0q4t8x2b6d",
1422− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1423− "brief": "Greet people by name, from the command line and the web page.",
1424− "status": "ready",
1425− "summary": "Name parsing first, then the two places that print the greeting.",
1426− "issues": [
1427− {
1428− "title": "Greeting should name the caller",
1429− "body": "Accept an optional name in `greet()` and use it.",
1430− "labels": [
1431− "feature"
1432− ],
1433− "done": [
1434− "`greet` prints \"Hello, ana!\" when given \"ana\", and \"Hello, world!\" with no argument."
1435− ],
1436− "files": [
1437− "src/greet.rs"
1438− ],
1439− "depends_on": [],
1440− "number": null
1441− },
1442− {
1443− "title": "Show the caller's name on the web page",
1444− "body": "Read `?name=` and pass it to `greet()`.",
1445− "labels": [
1446− "feature"
1447− ],
1448− "done": [
1449− "The page at / shows the name given in ?name=, escaped."
1450− ],
1451− "files": [
1452− "src/web.rs"
1453− ],
1454− "depends_on": [
1455− 1
1456− ],
1457− "number": null
1458− }
1459− ],
1460− "error": null,
1461− "author": {
1462− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1463− "username": "syntaqx",
1464− "kind": "user",
1465− "verified": false,
1466− "workspaces": []
1467− },
1468− "created_at": "2026-10-01T17:58:40.006Z",
1469− "finished_at": "2026-10-01T18:01:12.774Z",
1470− "progress": [],
1471− "exchanges": []
1472− },
1473− "notes": "A plan still `planning` after 20 minutes is reported as `failed`. `progress` follows each issue once the plan is applied."
1474− },
1475− "apply_plan": {
1476− "params": {
1477− "plan": "pln_01m43s9c4e8g2j6m0q4t8x2b6d"
1478− },
1479− "request": {
1480− "assign": true
1481− },
1482− "response": {
1483− "id": "pln_01m43s9c4e8g2j6m0q4t8x2b6d",
1484− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1485− "brief": "Greet people by name, from the command line and the web page.",
1486− "status": "applied",
1487− "summary": "Name parsing first, then the two places that print the greeting.",
1488− "issues": [
1489− {
1490− "title": "Greeting should name the caller",
1491− "body": "Accept an optional name in `greet()` and use it.",
1492− "labels": [
1493− "feature"
1494− ],
1495− "done": [
1496− "`greet` prints \"Hello, ana!\" when given \"ana\", and \"Hello, world!\" with no argument."
1497− ],
1498− "files": [
1499− "src/greet.rs"
1500− ],
1501− "depends_on": [],
1502− "number": 12
1503− },
1504− {
1505− "title": "Show the caller's name on the web page",
1506− "body": "Read `?name=` and pass it to `greet()`.",
1507− "labels": [
1508− "feature"
1509− ],
1510− "done": [
1511− "The page at / shows the name given in ?name=, escaped."
1512− ],
1513− "files": [
1514− "src/web.rs"
1515− ],
1516− "depends_on": [
1517− 1
1518− ],
1519− "number": 13
1520− }
1521− ],
1522− "error": null,
1523− "author": {
1524− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1525− "username": "syntaqx",
1526− "kind": "user",
1527− "verified": false,
1528− "workspaces": []
1529− },
1530− "created_at": "2026-10-01T17:58:40.006Z",
1531− "finished_at": "2026-10-01T18:01:12.774Z",
1532− "progress": [],
1533− "exchanges": []
1534− },
1535− "notes": "Each opened issue's `number` is filled in. Issues left out with `keep` stay `null`."
1536− },
1537− "list_pull_requests": {
1538− "query": {
1539− "state": "open"
1540− },
1541− "response": [
1542− {
1543− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1544− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1545− "number": 14,
1546− "issue": 12,
1547− "title": "Greeting should name the caller",
1548− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1549− "agent": "claude-code",
1550− "runtime": "external",
1551− "status": "open",
1552− "fork": {
1553− "namespace": "pulls",
1554− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1555− },
1556− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1557− "branch": null,
1558− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1559− "merge_base": null,
1560− "merged_by": null,
1561− "merged_at": null,
1562− "superseded_by": null,
1563− "check_status": "passed",
1564− "files": [
1565− {
1566− "path": "src/main.rs",
1567− "additions": 6,
1568− "deletions": 2
1569− }
1570− ],
1571− "assignees": [],
1572− "reviewers": [
1573− "ana"
1574− ],
1575− "team_reviewers": [],
1576− "author": {
1577− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1578− "username": "syntaqx",
1579− "kind": "user",
1580− "verified": false,
1581− "workspaces": []
1582− },
1583− "requested_by": null,
1584− "created_at": "2026-10-01T18:20:02.117Z",
1585− "updated_at": "2026-10-01T18:35:44.902Z",
1586− "labels": [],
1587− "milestone": null,
1588− "base": "main"
1589− }
1590− ],
1591− "notes": "Returns at most 100 pull requests, newest first. `check_status` is `queued`, `running`, `passed`, `failed`, `errored`, or `null` when no checks have run against the head."
1592− },
1593− "create_pull_request": {
1594− "request": {
1595− "issue": 12,
1596− "agent": "claude-code"
1597− },
1598− "response": {
1599− "pull": {
1600− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1601− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1602− "number": 14,
1603− "issue": 12,
1604− "title": "Greeting should name the caller",
1605− "body": null,
1606− "agent": "claude-code",
1607− "runtime": "external",
1608− "status": "draft",
1609− "fork": {
1610− "namespace": "pulls",
1611− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1612− },
1613− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1614− "branch": null,
1615− "head_commit": null,
1616− "merge_base": null,
1617− "merged_by": null,
1618− "merged_at": null,
1619− "superseded_by": null,
1620− "check_status": null,
1621− "files": [],
1622− "assignees": [],
1623− "reviewers": [],
1624− "labels": [],
1625− "milestone": null,
1626− "base": "main",
1627− "author": {
1628− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1629− "username": "syntaqx",
1630− "kind": "user",
1631− "verified": false,
1632− "workspaces": []
1633− },
1634− "requested_by": null,
1635− "created_at": "2026-10-01T18:20:02.117Z",
1636− "updated_at": "2026-10-01T18:20:02.117Z"
1637− },
1638− "git": {
1639− "remote": "https://g1t.sh/pulls/pr_01m43smh3vexsr5pmp60qwv0vs.git",
1640− "username": "syntaqx",
1641− "password": "your g1t access token"
1642− }
1643− },
1644− "notes": "`title` defaults to the issue's title, and is required when there is no `issue`. Push to `git.remote` with your username and an access token as the password.\n\nSend `branch` to open the pull request from a branch already pushed to the repository. No fork is made, `fork` is `null`, `git.remote` is the repository itself, and the pull request is `open` at once."
1645− },
1646− "get_pull_request": {
1647− "response": {
1648− "pull": {
1649− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1650− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1651− "number": 14,
1652− "issue": 12,
1653− "title": "Greeting should name the caller",
1654− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1655− "agent": "claude-code",
1656− "runtime": "external",
1657− "status": "open",
1658− "fork": {
1659− "namespace": "pulls",
1660− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1661− },
1662− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1663− "branch": null,
1664− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1665− "merge_base": null,
1666− "merged_by": null,
1667− "merged_at": null,
1668− "superseded_by": null,
1669− "check_status": "passed",
1670− "files": [
1671− {
1672− "path": "src/main.rs",
1673− "additions": 6,
1674− "deletions": 2
1675− }
1676− ],
1677− "assignees": [],
1678− "reviewers": [
1679− "ana"
1680− ],
1681− "team_reviewers": [
1682− "flagon-io/backend"
1683− ],
1684− "author": {
1685− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1686− "username": "syntaqx",
1687− "kind": "user",
1688− "verified": false,
1689− "workspaces": []
1690− },
1691− "requested_by": null,
1692− "created_at": "2026-10-01T18:20:02.117Z",
1693− "updated_at": "2026-10-01T18:35:44.902Z",
1694− "confidence": null,
1695− "labels": [],
1696− "milestone": null,
1697− "base": "main"
1698− },
1699− "issue": {
1700− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1701− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1702− "number": 12,
1703− "title": "Greeting should name the caller",
1704− "body": "Take a name from the first argument; fall back to world.",
1705− "labels": [
1706− "feature"
1707− ],
1708− "state": "open",
1709− "reason": null,
1710− "resolved_by": null,
1711− "author": {
1712− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1713− "username": "syntaqx",
1714− "kind": "user",
1715− "verified": false,
1716− "workspaces": []
1717− },
1718− "requested_by": null,
1719− "created_at": "2026-10-01T18:04:11.482Z",
1720− "updated_at": "2026-10-01T18:20:02.117Z",
1721− "closed_at": null,
1722− "pull_count": 1,
1723− "comment_count": 0,
1724− "assignees": [],
1725− "blocked_by": [],
1726− "queued": false,
1727− "agent": "claude-code",
1728− "milestone": null
1729− },
1730− "comments": [
1731− {
1732− "id": "cmt_01m43st6d0f4h8k2n6r0v4z8c2",
1733− "kind": "event",
1734− "author": {
1735− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1736− "username": "syntaqx",
1737− "kind": "user",
1738− "verified": false,
1739− "workspaces": []
1740− },
1741− "body": "marked this ready for review",
1742− "path": null,
1743− "line": null,
1744− "verdict": null,
1745− "created_at": "2026-10-01T18:33:10.420Z"
1746− }
1747− ],
1748− "checks": null,
1749− "overlaps": [],
1750− "behind": false,
1751− "review_pending": false,
1752− "lifecycle": null,
1753− "landing": false,
1754− "stalled": null,
1755− "messages": [
1756− {
1757− "id": "msg_01m43tx5egeh4t3f9zcnjenqvz",
1758− "author": "syntaqx",
1759− "body": "Keep \"world\" as the default when no name is given.",
1760− "created_at": "2026-10-01T18:25:00.310Z",
1761− "delivered_at": "2026-10-01T18:25:31.007Z",
1762− "kind": "message",
1763− "from_number": null,
1764− "to_number": 14,
1765− "answer": null,
1766− "declined": false
1767− }
1768− ],
1769− "statuses": [
1770− {
1771− "context": "CI / pull_request",
1772− "state": "success",
1773− "description": "CI passed",
1774− "target_url": "https://g1t.sh/syntaqx/hello/actions/runs/run_01m43sw8e2g6j0m4q8t2x6a0c4",
1775− "updated_at": "2026-10-01T18:35:44.902Z"
1776− }
1777− ],
1778− "required_checks": [
1779− {
1780− "name": "CI",
1781− "state": "success",
1782− "description": "CI passed",
1783− "target_url": "https://g1t.sh/syntaqx/hello/actions/runs/run_01m43sw8e2g6j0m4q8t2x6a0c4"
1784− }
1785− ],
1786− "code_owners": {
1787− "path": ".github/CODEOWNERS",
1788− "required": true,
1789− "reviews": [
1790− {
1791− "section": null,
1792− "line": 3,
1793− "pattern": "/src/",
1794− "owners": [
1795− "@flagon-io/backend"
1796− ],
1797− "files": [
1798− "src/main.rs"
1799− ],
1800− "optional": false,
1801− "required": 1,
1802− "approved_by": [],
1803− "changes_requested_by": [],
1804− "satisfied": false
1805− }
1806− ],
1807− "missing": "Code owners have not approved: @flagon-io/backend for /src/.",
1808− "errors": 0
1809− }
1810− },
1811− "notes": "| Field | |\n| --- | --- |\n| `pull.files` | The files it changes, with lines added and removed. |\n| `statuses` | Its checks: what each workflow run (or another tool, such as a deployment) reported on its head, as `pending`, `success`, `failure` or `error`, with a link to the run. |\n| `required_checks` | Each check the default branch requires (see [`update_repo_settings`](/reference/api/repositories/update-repo-settings/)), as it stands on the head: `success`, `failure`, `pending`, or `expected` when nothing has reported it yet. It merges only once all are `success`. |\n| `checks` | Set when the merge queue took it out, with why in `error`. Older pull requests may show a run of commands from their issue here, from before checks were workflows. |\n| `overlaps` | Other pull requests in progress that change the same files. |\n| `behind` | Whether the default branch has moved since it was made. |\n| `landing` | Whether it is being brought up to date to land. |\n| `lifecycle` | For a pull request g1t is seeing through: its stage, such as `working`, `checking`, `reviewing` or `needs_you`. |\n| `comments` | Comments, reviews and events, with `path`, `line` and `verdict`. |\n| `messages` | Messages sent to the agent working on it. |\n| `pull.reviewers`, `pull.team_reviewers` | The people asked to review it, `g1t` among them when a g1t agent was, and the teams, as `workspace/team`. Change them with [`request_reviewers`](/reference/api/pull-requests/request-reviewers/). |\n| `code_owners` | Present when the branch it merges into has a CODEOWNERS file: its `path`, whether code owners' approval is `required` there, `reviews` (one per section and rule that owns a changed file: `section`, `line`, `pattern`, `owners`, `files`, `optional`, the approvals `required`, `approved_by`, `changes_requested_by` and `satisfied`), what is still `missing`, as the merge box says it, and how many `errors` the file has; [`get_codeowners_errors`](/reference/api/repositories/get-codeowners-errors/) lists them. |\n| `mergeable` | Whether it merges cleanly into its target: `clean`, `conflicting`, `checking` (being worked out) or `unknown`. Worked out ahead of time whenever it or its target moves. |\n| `conflicts` | When `mergeable` is `conflicting`, the files that conflict. Resolve them by merging the target in, or have g1t do it. |\n| `earlier_checks` | Earlier records like `checks`, newest first. |\n\nChecks are the repository's workflows: they run on `pull_request` events when it is opened, marked ready and pushed to. Read why one failed with [`get_workflow_run`](/reference/api/actions/get-workflow-run/) and [`get_job_logs`](/reference/api/actions/get-job-logs/)."
1812− },
1813− "get_pull_request_changes": {
1814− "response": {
1815− "base": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
1816− "head": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1817− "files": [
1818− {
1819− "path": "src/main.rs",
1820− "status": "modified",
1821− "additions": 1,
1822− "deletions": 1,
1823− "binary": false,
1824− "hunks": [
1825− {
1826− "lines": [
1827− {
1828− "kind": "context",
1829− "old": 3,
1830− "new": 3,
1831− "text": "fn main() {"
1832− },
1833− {
1834− "kind": "delete",
1835− "old": 4,
1836− "new": null,
1837− "text": " println!(\"Hello, world!\");"
1838− },
1839− {
1840− "kind": "add",
1841− "old": null,
1842− "new": 4,
1843− "text": " println!(\"Hello, {}!\", std::env::args().nth(1).unwrap_or(\"world\".into()));"
1844− },
1845− {
1846− "kind": "context",
1847− "old": 5,
1848− "new": 5,
1849− "text": "}"
1850− }
1851− ]
1852− }
1853− ]
1854− }
1855− ],
1856− "truncated": false
1857− },
1858− "notes": "A file's `status` is `added`, `modified` or `deleted`. A binary file has no `hunks`. In a line, `old` is `null` when it was added and `new` is `null` when it was deleted."
1859− },
1860− "mark_pull_request_ready": {
1861− "request": {
1862− "summary": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\"."
1863− },
1864− "response": {
1865− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1866− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1867− "number": 14,
1868− "issue": 12,
1869− "title": "Greeting should name the caller",
1870− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1871− "agent": "claude-code",
1872− "runtime": "external",
1873− "status": "open",
1874− "fork": {
1875− "namespace": "pulls",
1876− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1877− },
1878− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1879− "branch": null,
1880− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1881− "merge_base": null,
1882− "merged_by": null,
1883− "merged_at": null,
1884− "superseded_by": null,
1885− "check_status": null,
1886− "files": [
1887− {
1888− "path": "src/main.rs",
1889− "additions": 6,
1890− "deletions": 2
1891− }
1892− ],
1893− "assignees": [],
1894− "reviewers": [],
1895− "labels": [],
1896− "milestone": null,
1897− "base": "main",
1898− "author": {
1899− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1900− "username": "syntaqx",
1901− "kind": "user",
1902− "verified": false,
1903− "workspaces": []
1904− },
1905− "requested_by": null,
1906− "created_at": "2026-10-01T18:20:02.117Z",
1907− "updated_at": "2026-10-01T18:33:10.398Z"
1908− }
1909− },
1910− "review_pull_request": {
1911− "request": {
1912− "verdict": "request_changes",
1913− "body": "Trim the name before using it."
1914− },
1915− "response": {
1916− "id": "cmt_01m43sx9f3h7k1n5r9v3z7d1g5",
1917− "kind": "comment",
1918− "author": {
1919− "id": "usr_01kz9d3f7h1k5n9r3v7z1c5g9b",
1920− "username": "ana",
1921− "kind": "user",
1922− "verified": true,
1923− "workspaces": [
1924− {
1925− "slug": "flagon-io",
1926− "role": "member"
1927− }
1928− ]
1929− },
1930− "body": "Trim the name before using it.",
1931− "path": null,
1932− "line": null,
1933− "verdict": "request_changes",
1934− "created_at": "2026-10-01T18:40:05.019Z"
1935− }
1936− },
1937− "request_reviewers": {
1938− "params": {
1939− "owner": "flagon-io",
1940− "name": "hello",
1941− "number": 14
1942− },
1943− "request": {
1944− "reviewers": [
1945− "bo"
1946− ],
1947− "team_reviewers": [
1948− "backend"
1949− ]
1950− },
1951− "response": {
1952− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1953− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1954− "number": 14,
1955− "issue": 12,
1956− "title": "Greeting should name the caller",
1957− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1958− "agent": "claude-code",
1959− "runtime": "external",
1960− "status": "open",
1961− "fork": {
1962− "namespace": "pulls",
1963− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1964− },
1965− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1966− "branch": null,
1967− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1968− "merge_base": null,
1969− "merged_by": null,
1970− "merged_at": null,
1971− "superseded_by": null,
1972− "check_status": "passed",
1973− "files": [
1974− {
1975− "path": "src/main.rs",
1976− "additions": 6,
1977− "deletions": 2
1978− }
1979− ],
1980− "assignees": [],
1981− "reviewers": [
1982− "ana",
1983− "bo"
1984− ],
1985− "team_reviewers": [
1986− "flagon-io/backend"
1987− ],
1988− "author": {
1989− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1990− "username": "syntaqx",
1991− "kind": "user",
1992− "verified": false,
1993− "workspaces": []
1994− },
1995− "requested_by": null,
1996− "created_at": "2026-10-01T18:20:02.117Z",
1997− "updated_at": "2026-10-01T18:40:12.331Z"
1998− },
1999− "notes": "Adds to who is asked: `reviewers` by username (`g1t` asks a g1t agent), `team_reviewers` as `workspace/team`, or a team's slug in the repository's workspace. A team with review assignment on has the people it picks added to `reviewers`, and stays in `team_reviewers`. Each is told in their inbox. Nobody is asked to review their own pull request. `422` for someone who is not an account, or a team that does not exist or that you cannot see. Whoever opened it, or the Triage role or higher, while it is open. See [Pull requests](/guides/pull-requests/) and [Teams](/guides/teams/)."
2000− },
2001− "remove_requested_reviewers": {
2002− "params": {
2003− "owner": "flagon-io",
2004− "name": "hello",
2005− "number": 14
2006− },
2007− "request": {
2008− "reviewers": [
2009− "bo"
2010− ],
2011− "team_reviewers": [
2012− "flagon-io/backend"
2013− ]
2014− },
2015− "response": {
2016− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
2017− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
2018− "number": 14,
2019− "issue": 12,
2020− "title": "Greeting should name the caller",
2021− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
2022− "agent": "claude-code",
2023− "runtime": "external",
2024− "status": "open",
2025− "fork": {
2026− "namespace": "pulls",
2027− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
2028− },
2029− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
2030− "branch": null,
2031− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2032− "merge_base": null,
2033− "merged_by": null,
2034− "merged_at": null,
2035− "superseded_by": null,
2036− "check_status": "passed",
2037− "files": [
2038− {
2039− "path": "src/main.rs",
2040− "additions": 6,
2041− "deletions": 2
2042− }
2043− ],
2044− "assignees": [],
2045− "reviewers": [
2046− "ana"
2047− ],
2048− "team_reviewers": [],
2049− "author": {
2050− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
2051− "username": "syntaqx",
2052− "kind": "user",
2053− "verified": false,
2054− "workspaces": []
2055− },
2056− "requested_by": null,
2057− "created_at": "2026-10-01T18:20:02.117Z",
2058− "updated_at": "2026-10-01T18:41:30.904Z"
2059− },
2060− "notes": "Takes them off who is asked; anyone not asked is ignored. Reviews they already gave stay, as do the people a team's review assignment picked: remove them by username."
2061− },
2062− "merge_pull_request": {
2063− "request": {
2064− "keep_issue_open": false
2065− },
2066− "response": {
2067− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
2068− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
2069− "number": 14,
2070− "issue": 12,
2071− "title": "Greeting should name the caller",
2072− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
2073− "agent": "claude-code",
2074− "runtime": "external",
2075− "status": "merged",
2076− "fork": {
2077− "namespace": "pulls",
2078− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
2079− },
2080− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
2081− "branch": null,
2082− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2083− "merge_base": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
2084− "merged_by": "syntaqx",
2085− "merged_at": "2026-10-01T18:52:17.093Z",
2086− "superseded_by": null,
2087− "check_status": "passed",
2088− "files": [
2089− {
2090− "path": "src/main.rs",
2091− "additions": 6,
2092− "deletions": 2
2093− }
2094− ],
2095− "assignees": [],
2096− "reviewers": [
2097− "ana"
2098− ],
2099− "labels": [],
2100− "milestone": null,
2101− "base": "main",
2102− "author": {
2103− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
2104− "username": "syntaqx",
2105− "kind": "user",
2106− "verified": false,
2107− "workspaces": []
2108− },
2109− "requested_by": null,
2110− "created_at": "2026-10-01T18:20:02.117Z",
2111− "updated_at": "2026-10-01T18:52:17.093Z"
2112− },
2113− "notes": "A draft, or one whose checks have not passed, answers `409`. A pull request still `open` in the response has not landed yet: `landing` is true on it while it is brought up to date, and [get the merge queue](/reference/api/pull-requests/get-merge-queue/) shows it waiting in the [merge queue](/guides/merge-queue/). Merging records the pull request in the issue's `resolved_by` and sets `superseded_by` on the pull requests it closes."
2114− },
2115− "close_pull_request": {
2116− "response": {
2117− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
2118− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
2119− "number": 14,
2120− "issue": 12,
2121− "title": "Greeting should name the caller",
2122− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
2123− "agent": "claude-code",
2124− "runtime": "external",
2125− "status": "closed",
2126− "fork": {
2127− "namespace": "pulls",
2128− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
2129− },
2130− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
2131− "branch": null,
2132− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2133− "merge_base": null,
2134− "merged_by": null,
2135− "merged_at": null,
2136− "superseded_by": null,
2137− "check_status": null,
2138− "files": [
2139− {
2140− "path": "src/main.rs",
2141− "additions": 6,
2142− "deletions": 2
2143− }
2144− ],
2145− "assignees": [],
2146− "reviewers": [],
2147− "labels": [],
2148− "milestone": null,
2149− "base": "main",
2150− "author": {
2151− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
2152− "username": "syntaqx",
2153− "kind": "user",
2154− "verified": false,
2155− "workspaces": []
2156− },
2157− "requested_by": null,
2158− "created_at": "2026-10-01T18:20:02.117Z",
2159− "updated_at": "2026-10-01T19:02:48.760Z"
2160− }
2161− },
2162− "get_merge_queue": {
2163− "response": {
2164− "enabled": true,
2165− "active": [
2166− {
2167− "id": "qen_01m43rn0qsft1tpap1awkewzbb",
2168− "number": 14,
2169− "title": "Greeting should name the caller",
2170− "agent": "claude-code",
2171− "state": "testing",
2172− "ahead": [],
2173− "base_commit": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
2174− "combined_commit": null,
2175− "error": null,
2176− "results": [],
2177− "enqueued_by": "syntaqx",
2178− "created_at": "2026-10-04T15:31:20.441Z",
2179− "finished_at": null
2180− }
2181− ],
2182− "recent": [
2183− {
2184− "id": "qen_01m43khqjmeb5a1magayrnk63z",
2185− "number": 11,
2186− "title": "Fix trailing newline in greeting",
2187− "agent": "g1t",
2188− "state": "landed",
2189− "ahead": [],
2190− "base_commit": "4b1d7e9c2a5f8e3d6c0b9a7e5d3c1b8a6f4e2d0c",
2191− "combined_commit": "c3e8a1f6d4b2097e5c3a1f8d6b4e2c0a9f7d5b3e",
2192− "error": null,
2193− "results": [
2194− {
2195− "command": "cargo test",
2196− "passed": true,
2197− "exit_code": 0,
2198− "output": "test result: ok. 12 passed; 0 failed\n",
2199− "duration_ms": 48211
2200− }
2201− ],
2202− "enqueued_by": "g1t",
2203− "created_at": "2026-10-04T14:02:09.876Z",
2204− "finished_at": "2026-10-04T14:09:55.102Z"
2205− }
2206− ]
2207− },
2208− "notes": "An entry's `state` is `waiting`, `testing`, `passed`, `failed`, `landed` or `removed`. `active` is in queue order; `recent` holds at most 20, newest first."
2209− },
2210− "message_agent": {
2211− "request": {
2212− "body": "Keep \"world\" as the default when no name is given."
2213− },
2214− "response": {
2215− "id": "msg_01m43tx5egeh4t3f9zcnjenqvz",
2216− "author": "syntaqx",
2217− "body": "Keep \"world\" as the default when no name is given.",
2218− "created_at": "2026-10-01T18:25:00.310Z",
2219− "delivered_at": null,
2220− "kind": "message",
2221− "from_number": null,
2222− "to_number": 14,
2223− "answer": null,
2224− "declined": false
2225− },
2226− "notes": "The response is the message. `delivered_at` is set once the agent has read it."
2227− },
2228− "answer_message": {
2229− "params": {
2230− "id": "msg_01m43t66tde8hs2vpxhh3v8tqw"
2231− },
2232− "request": {
2233− "body": "No. greet() keeps its name; only greet_named() is added."
2234− },
2235− "response": {
2236− "id": "msg_01m43t66tde8hs2vpxhh3v8tqw",
2237− "author": "g1t",
2238− "body": "Are you renaming greet() in src/lib.rs? I need to call it from #16.",
2239− "created_at": "2026-10-01T18:58:12.301Z",
2240− "delivered_at": "2026-10-01T18:58:40.117Z",
2241− "kind": "question",
2242− "from_number": 16,
2243− "to_number": 14,
2244− "answer": "No. greet() keeps its name; only greet_named() is added.",
2245− "declined": false
2246− },
2247− "notes": "The response is the question or handoff that was answered, with `answer` and `declined` filled in."
2248− },
2249− "take_messages": {
2250− "response": [
2251− {
2252− "id": "msg_01m43tx5egeh4t3f9zcnjenqvz",
2253− "author": "syntaqx",
2254− "body": "Keep \"world\" as the default when no name is given.",
2255− "created_at": "2026-10-01T18:25:00.310Z",
2256− "delivered_at": "2026-10-01T18:25:31.007Z",
2257− "kind": "message",
2258− "from_number": null,
2259− "to_number": 14,
2260− "answer": null,
2261− "declined": false
2262− }
2263− ],
2264− "notes": "Only a g1t agent's token can take messages. They come oldest first, and each is marked delivered."
2265− },
2266− "read_session": {
2267− "query": {
2268− "after": 0
2269− },
2270− "response": [
2271− {
2272− "seq": 1,
2273− "kind": "prompt",
2274− "text": "Make the greeting name the caller (issue #12).",
2275− "tool": null,
2276− "commit": null,
2277− "at": "2026-10-01T18:21:00.004Z"
2278− },
2279− {
2280− "seq": 2,
2281− "kind": "tool_call",
2282− "text": "cargo test",
2283− "tool": "bash",
2284− "commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2285− "at": "2026-10-01T18:30:12.660Z"
2286− }
2287− ]
2288− },
2289− "record_session": {
2290− "request": {
2291− "entries": [
2292− {
2293− "kind": "message",
2294− "text": "Reading src/main.rs."
2295− },
2296− {
2297− "kind": "tool_call",
2298− "text": "cargo test",
2299− "tool": "bash"
2300− }
2301− ]
2302− },
2303− "response": {
2304− "count": 2
2305− },
2306− "notes": "Up to 200 entries can be appended per request. Each is recorded against the pull request's head commit at the time. See [sessions and why-blame](/guides/why-blame/)."
2307− },
2308− "list_workflows": {
2309− "response": [
2310− {
2311− "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2312− "path": ".g1t/workflows/ci.yml",
2313− "name": "CI",
2314− "events": [
2315− "push",
2316− "pull_request",
2317− "workflow_dispatch"
2318− ],
2319− "state": "active",
2320− "error": null,
2321− "notes": [
2322− {
2323− "severity": "unsupported",
2324− "job": "test",
2325− "message": "`services` containers (such as a database) are not started on g1t yet."
2326− }
2327− ],
2328− "dispatch": {
2329− "debug": {
2330− "description": "Verbose logs",
2331− "type": "boolean",
2332− "default": false
2333− }
2334− },
2335− "last_run": {
2336− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2337− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2338− "path": ".g1t/workflows/ci.yml",
2339− "name": "CI",
2340− "title": "Greeting should name the caller",
2341− "number": 12,
2342− "attempt": 1,
2343− "event": "push",
2344− "ref": "refs/heads/main",
2345− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2346− "pull": null,
2347− "status": "completed",
2348− "conclusion": "success",
2349− "error": null,
2350− "actor": "syntaqx",
2351− "created_at": "2026-10-04T15:42:07.318Z",
2352− "started_at": "2026-10-04T15:42:09.020Z",
2353− "finished_at": "2026-10-04T15:44:31.877Z"
2354− }
2355− },
2356− {
2357− "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2358− "path": ".g1t/workflows/nightly.yml",
2359− "name": "Nightly",
2360− "events": [
2361− "schedule"
2362− ],
2363− "state": "disabled",
2364− "error": null,
2365− "notes": [],
2366− "dispatch": null,
2367− "last_run": null
2368− }
2369− ],
2370− "notes": "`state` is `active` or `disabled`. `dispatch` holds the `workflow_dispatch` inputs, or is `null` when the workflow cannot be run by hand. See [GitHub Actions](/guides/actions/)."
2371− },
2372− "list_workflow_runs": {
2373− "query": {
2374− "workflow": "ci.yml",
2375− "branch": "main",
2376− "per_page": 20
2377− },
2378− "response": [
2379− {
2380− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2381− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2382− "path": ".g1t/workflows/ci.yml",
2383− "name": "CI",
2384− "title": "Greeting should name the caller",
2385− "number": 12,
2386− "attempt": 1,
2387− "event": "push",
2388− "ref": "refs/heads/main",
2389− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2390− "pull": null,
2391− "status": "completed",
2392− "conclusion": "success",
2393− "error": null,
2394− "actor": "syntaqx",
2395− "created_at": "2026-10-04T15:42:07.318Z",
2396− "started_at": "2026-10-04T15:42:09.020Z",
2397− "finished_at": "2026-10-04T15:44:31.877Z"
2398− }
2399− ],
2400− "notes": "A run's `status` is `queued`, `pending` (waiting for its concurrency group), `in_progress` or `completed`; `conclusion` is set once it completes."
2401− },
2402− "list_runs_of_workflow": {
2403− "params": {
2404− "workflow": "ci.yml"
2405− },
2406− "query": {
2407− "branch": "main",
2408− "per_page": 20
2409− },
2410− "response": [
2411− {
2412− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2413− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2414− "path": ".g1t/workflows/ci.yml",
2415− "name": "CI",
2416− "title": "Greeting should name the caller",
2417− "number": 12,
2418− "attempt": 1,
2419− "event": "push",
2420− "ref": "refs/heads/main",
2421− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2422− "pull": null,
2423− "status": "completed",
2424− "conclusion": "success",
2425− "error": null,
2426− "actor": "syntaqx",
2427− "created_at": "2026-10-04T15:42:07.318Z",
2428− "started_at": "2026-10-04T15:42:09.020Z",
2429− "finished_at": "2026-10-04T15:44:31.877Z"
2430− }
2431− ]
2432− },
2433− "get_workflow_run": {
2434− "params": {
2435− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2436− },
2437− "response": {
2438− "run": {
2439− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2440− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2441− "path": ".g1t/workflows/ci.yml",
2442− "name": "CI",
2443− "title": "Greeting should name the caller",
2444− "number": 12,
2445− "attempt": 1,
2446− "event": "push",
2447− "ref": "refs/heads/main",
2448− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2449− "pull": null,
2450− "status": "completed",
2451− "conclusion": "failure",
2452− "error": null,
2453− "actor": "syntaqx",
2454− "created_at": "2026-10-04T15:42:07.318Z",
2455− "started_at": "2026-10-04T15:42:09.020Z",
2456− "finished_at": "2026-10-04T15:44:31.877Z"
2457− },
2458− "jobs": [
2459− {
2460− "id": "job_01kpx7b3d0e4f8g2h6j0k4m8ns",
2461− "run_id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2462− "key": "test",
2463− "name": "test",
2464− "needs": [],
2465− "status": "completed",
2466− "conclusion": "failure",
2467− "steps": [
2468− {
2469− "number": 1,
2470− "name": "Run actions/checkout@v4",
2471− "status": "completed",
2472− "conclusion": "success",
2473− "started_at": "2026-10-04T15:42:10.101Z",
2474− "finished_at": "2026-10-04T15:42:12.433Z"
2475− },
2476− {
2477− "number": 2,
2478− "name": "Run cargo test",
2479− "status": "completed",
2480− "conclusion": "failure",
2481− "started_at": "2026-10-04T15:42:12.440Z",
2482− "finished_at": "2026-10-04T15:44:30.902Z"
2483− }
2484− ],
2485− "annotations": [
2486− {
2487− "level": "error",
2488− "message": "assertion failed: greeting names the caller",
2489− "title": "greet",
2490− "file": "src/main.rs",
2491− "line": 41
2492− }
2493− ],
2494− "reason": null,
2495− "started_at": "2026-10-04T15:42:09.020Z",
2496− "finished_at": "2026-10-04T15:44:31.002Z"
2497− },
2498− {
2499− "id": "job_01kpx7b3d0e4f8g2h6j0k4m8nt",
2500− "run_id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2501− "key": "deploy",
2502− "name": "deploy",
2503− "needs": [
2504− "test"
2505− ],
2506− "status": "completed",
2507− "conclusion": "skipped",
2508− "steps": [],
2509− "annotations": [],
2510− "reason": "A job it needs did not succeed.",
2511− "started_at": null,
2512− "finished_at": "2026-10-04T15:44:31.877Z"
2513− }
2514− ],
2515− "notes": [
2516− {
2517− "severity": "unsupported",
2518− "job": "test",
2519− "message": "`services` containers (such as a database) are not started on g1t yet."
2520− }
2521− ]
2522− }
2523− },
2524− "get_job_logs": {
2525− "params": {
2526− "job": "job_01kpx7b3d0e4f8g2h6j0k4m8ns"
2527− },
2528− "query": {
2529− "after": 0
2530− },
2531− "response": {
2532− "chunks": [
2533− {
2534− "seq": 1,
2535− "step": 0,
2536− "text": "Preparing the sandbox\n"
2537− },
2538− {
2539− "seq": 2,
2540− "step": 2,
2541− "text": "> cargo test\ntest greet ... FAILED\n"
2542− }
2543− ],
2544− "done": true
2545− },
2546− "notes": "Returns at most 500 chunks. Step 0 is the job's setup. While `done` is false, call again with the last `seq` as `after`."
2547− },
2548− "dispatch_workflow": {
2549− "params": {
2550− "workflow": "ci.yml"
2551− },
2552− "request": {
2553− "ref": "main",
2554− "inputs": {
2555− "debug": true
2556− }
2557− },
2558− "response": {
2559− "id": "run_01kpx8d4e7f0g3h6j9k2m5n8pq",
2560− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2561− "path": ".g1t/workflows/ci.yml",
2562− "name": "CI",
2563− "title": "CI run by syntaqx",
2564− "number": 13,
2565− "attempt": 1,
2566− "event": "workflow_dispatch",
2567− "ref": "refs/heads/main",
2568− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2569− "pull": null,
2570− "status": "queued",
2571− "conclusion": null,
2572− "error": null,
2573− "actor": "syntaqx",
2574− "created_at": "2026-10-04T16:30:00.512Z",
2575− "started_at": null,
2576− "finished_at": null
2577− }
2578− },
2579− "cancel_workflow_run": {
2580− "params": {
2581− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2582− },
2583− "response": {
2584− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2585− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2586− "path": ".g1t/workflows/ci.yml",
2587− "name": "CI",
2588− "title": "Greeting should name the caller",
2589− "number": 12,
2590− "attempt": 1,
2591− "event": "push",
2592− "ref": "refs/heads/main",
2593− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2594− "pull": null,
2595− "status": "completed",
2596− "conclusion": "cancelled",
2597− "error": null,
2598− "actor": "syntaqx",
2599− "created_at": "2026-10-04T15:42:07.318Z",
2600− "started_at": "2026-10-04T15:42:09.020Z",
2601− "finished_at": "2026-10-04T15:44:31.877Z"
2602− }
2603− },
2604− "rerun_workflow_run": {
2605− "params": {
2606− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2607− },
2608− "request": {
2609− "failed_only": true
2610− },
2611− "response": {
2612− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2613− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2614− "path": ".g1t/workflows/ci.yml",
2615− "name": "CI",
2616− "title": "Greeting should name the caller",
2617− "number": 12,
2618− "attempt": 2,
2619− "event": "push",
2620− "ref": "refs/heads/main",
2621− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2622− "pull": null,
2623− "status": "queued",
2624− "conclusion": null,
2625− "error": null,
2626− "actor": "syntaqx",
2627− "created_at": "2026-10-04T15:42:07.318Z",
2628− "started_at": null,
2629− "finished_at": null
2630− },
2631− "notes": "The run keeps its id; `attempt` goes up by one."
2632− },
2633− "rerun_failed_jobs": {
2634− "params": {
2635− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2636− },
2637− "response": {
2638− "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2639− "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2640− "path": ".g1t/workflows/ci.yml",
2641− "name": "CI",
2642− "title": "Greeting should name the caller",
2643− "number": 12,
2644− "attempt": 2,
2645− "event": "push",
2646− "ref": "refs/heads/main",
2647− "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2648− "pull": null,
2649− "status": "queued",
2650− "conclusion": null,
2651− "error": null,
2652− "actor": "syntaqx",
2653− "created_at": "2026-10-04T15:42:07.318Z",
2654− "started_at": null,
2655− "finished_at": null
2656− }
2657− },
2658− "update_workflow": {
2659− "params": {
2660− "workflow": "nightly.yml"
2661− },
2662− "request": {
2663− "enabled": false
2664− },
2665− "response": {
2666− "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2667− "path": ".g1t/workflows/nightly.yml",
2668− "name": "Nightly",
2669− "events": [
2670− "schedule"
2671− ],
2672− "state": "disabled",
2673− "error": null,
2674− "notes": [],
2675− "dispatch": null,
2676− "last_run": null
2677− }
2678− },
2679− "enable_workflow": {
2680− "params": {
2681− "workflow": "nightly.yml"
2682− },
2683− "response": {
2684− "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2685− "path": ".g1t/workflows/nightly.yml",
2686− "name": "Nightly",
2687− "events": [
2688− "schedule"
2689− ],
2690− "state": "active",
2691− "error": null,
2692− "notes": [],
2693− "dispatch": null,
2694− "last_run": null
2695− }
2696− },
2697− "disable_workflow": {
2698− "params": {
2699− "workflow": "nightly.yml"
2700− },
2701− "response": {
2702− "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2703− "path": ".g1t/workflows/nightly.yml",
2704− "name": "Nightly",
2705− "events": [
2706− "schedule"
2707− ],
2708− "state": "disabled",
2709− "error": null,
2710− "notes": [],
2711− "dispatch": null,
2712− "last_run": null
2713− }
2714− },
2715− "list_actions_secrets": {
2716− "response": [
2717− {
2718− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ab",
2719− "name": "NPM_TOKEN",
2720− "kind": "secret",
2721− "value": null,
2722− "scope": "workspace",
2723− "updated_at": "2026-10-01T09:12:44.020Z",
2724− "available_to": [
2725− "workflows"
2726− ],
2727− "environments": [],
2728− "projects": [],
2729− "note": null,
2730− "updated_by": "syntaqx"
2731− },
2732− {
2733− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ac",
2734− "name": "STRIPE_KEY",
2735− "kind": "secret",
2736− "value": null,
2737− "scope": "project",
2738− "updated_at": "2026-10-04T15:42:07.318Z",
2739− "available_to": [
2740− "workflows",
2741− "deployments"
2742− ],
2743− "environments": [
2744− "production"
2745− ],
2746− "projects": [],
2747− "note": "Rotate in the Stripe dashboard.",
2748− "updated_by": "syntaqx"
2749− }
2750− ],
2751− "notes": "Values are never returned. A repository's list includes the workspace's rows that reach it, with `scope` set to `workspace`. Empty `environments` means every environment."
2752− },
2753− "list_actions_secrets_for_workspace": {
2754− "params": {
2755− "workspace": "flagon-io"
2756− },
2757− "response": [
2758− {
2759− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ab",
2760− "name": "NPM_TOKEN",
2761− "kind": "secret",
2762− "value": null,
2763− "scope": "workspace",
2764− "updated_at": "2026-10-04T15:42:07.318Z",
2765− "available_to": [
2766− "workflows"
2767− ],
2768− "environments": [],
2769− "projects": [],
2770− "note": null,
2771− "updated_by": "syntaqx"
2772− }
2773− ],
2774− "notes": "Values are never returned. A repository's list includes the workspace's rows that reach it, with `scope` set to `workspace`. Empty `environments` means every environment."
2775− },
2776− "set_actions_secret": {
2777− "params": {
2778− "setting": "STRIPE_KEY"
2779− },
2780− "request": {
2781− "value": "sk_live_…",
2782− "available_to": [
2783− "workflows",
2784− "deployments"
2785− ],
2786− "environments": [
2787− "production"
2788− ]
2789− },
2790− "response": {
2791− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ac",
2792− "name": "STRIPE_KEY",
2793− "kind": "secret",
2794− "value": null,
2795− "scope": "project",
2796− "updated_at": "2026-10-04T15:42:07.318Z",
2797− "available_to": [
2798− "workflows",
2799− "deployments"
2800− ],
2801− "environments": [
2802− "production"
2803− ],
2804− "projects": [],
2805− "note": null,
2806− "updated_by": "syntaqx"
2807− },
2808− "notes": "Keys are uppercased. See [secrets and variables](/guides/secrets-and-variables/)."
2809− },
2810− "set_actions_secret_for_workspace": {
2811− "params": {
2812− "workspace": "flagon-io",
2813− "setting": "NPM_TOKEN"
2814− },
2815− "request": {
2816− "value": "npm_…",
2817− "projects": [
2818− "hello"
2819− ]
2820− },
2821− "response": {
2822− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ac",
2823− "name": "NPM_TOKEN",
2824− "kind": "secret",
2825− "value": null,
2826− "scope": "workspace",
2827− "updated_at": "2026-10-04T15:42:07.318Z",
2828− "available_to": [
2829− "workflows"
2830− ],
2831− "environments": [],
2832− "projects": [
2833− "hello"
2834− ],
2835− "note": null,
2836− "updated_by": "syntaqx"
2837− }
2838− },
2839− "delete_actions_secret": {
2840− "params": {
2841− "setting": "STRIPE_KEY"
2842− },
2843− "response": true
2844− },
2845− "delete_actions_secret_for_workspace": {
2846− "params": {
2847− "workspace": "flagon-io",
2848− "setting": "NPM_TOKEN"
2849− },
2850− "response": true
2851− },
2852− "list_actions_variables": {
2853− "response": [
2854− {
2855− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2856− "name": "NODE_VERSION",
2857− "kind": "variable",
2858− "value": "20",
2859− "scope": "project",
2860− "updated_at": "2026-10-04T15:42:07.318Z",
2861− "available_to": [
2862− "workflows",
2863− "deployments"
2864− ],
2865− "environments": [],
2866− "projects": [],
2867− "note": null,
2868− "updated_by": "syntaqx"
2869− }
2870− ],
2871− "notes": "A repository's list includes the workspace's rows that reach it, with `scope` set to `workspace`. Empty `environments` means every environment."
2872− },
2873− "list_actions_variables_for_workspace": {
2874− "params": {
2875− "workspace": "flagon-io"
2876− },
2877− "response": [
2878− {
2879− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2880− "name": "NODE_VERSION",
2881− "kind": "variable",
2882− "value": "20",
2883− "scope": "workspace",
2884− "updated_at": "2026-10-04T15:42:07.318Z",
2885− "available_to": [
2886− "workflows",
2887− "deployments"
2888− ],
2889− "environments": [],
2890− "projects": [],
2891− "note": null,
2892− "updated_by": "syntaqx"
2893− }
2894− ]
2895− },
2896− "set_actions_variable": {
2897− "request": {
2898− "setting": "NODE_VERSION",
2899− "value": "20"
2900− },
2901− "response": {
2902− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2903− "name": "NODE_VERSION",
2904− "kind": "variable",
2905− "value": "20",
2906− "scope": "project",
2907− "updated_at": "2026-10-04T15:42:07.318Z",
2908− "available_to": [
2909− "workflows",
2910− "deployments"
2911− ],
2912− "environments": [],
2913− "projects": [],
2914− "note": null,
2915− "updated_by": "syntaqx"
2916− },
2917− "notes": "GitHub's clients send the key as `name`; that is accepted too."
2918− },
2919− "set_actions_variable_for_workspace": {
2920− "params": {
2921− "workspace": "flagon-io"
2922− },
2923− "request": {
2924− "setting": "NODE_VERSION",
2925− "value": "20"
2926− },
2927− "response": {
2928− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2929− "name": "NODE_VERSION",
2930− "kind": "variable",
2931− "value": "20",
2932− "scope": "workspace",
2933− "updated_at": "2026-10-04T15:42:07.318Z",
2934− "available_to": [
2935− "workflows",
2936− "deployments"
2937− ],
2938− "environments": [],
2939− "projects": [],
2940− "note": null,
2941− "updated_by": "syntaqx"
2942− }
2943− },
2944− "update_actions_variable": {
2945− "params": {
2946− "setting": "NODE_VERSION"
2947− },
2948− "request": {
2949− "value": "22"
2950− },
2951− "response": {
2952− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2953− "name": "NODE_VERSION",
2954− "kind": "variable",
2955− "value": "22",
2956− "scope": "project",
2957− "updated_at": "2026-10-04T15:42:07.318Z",
2958− "available_to": [
2959− "workflows",
2960− "deployments"
2961− ],
2962− "environments": [],
2963− "projects": [],
2964− "note": null,
2965− "updated_by": "syntaqx"
2966− }
2967− },
2968− "update_actions_variable_for_workspace": {
2969− "params": {
2970− "workspace": "flagon-io",
2971− "setting": "NODE_VERSION"
2972− },
2973− "request": {
2974− "value": "22"
2975− },
2976− "response": {
2977− "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2978− "name": "NODE_VERSION",
2979− "kind": "variable",
2980− "value": "22",
2981− "scope": "workspace",
2982− "updated_at": "2026-10-04T15:42:07.318Z",
2983− "available_to": [
2984− "workflows",
2985− "deployments"
2986− ],
2987− "environments": [],
2988− "projects": [],
2989− "note": null,
2990− "updated_by": "syntaqx"
2991− }
2992− },
2993− "delete_actions_variable": {
2994− "params": {
2995− "setting": "NODE_VERSION"
2996− },
2997− "response": true
2998− },
2999− "delete_actions_variable_for_workspace": {
3000− "params": {
3001− "workspace": "flagon-io",
3002− "setting": "NODE_VERSION"
3003− },
3004− "response": true
3005− },
3006− "list_runners": {
3007− "response": [
3008− {
3009− "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z",
3010− "name": "build-01",
3011− "workspace": "flagon-io",
3012− "repo": null,
3013− "group": "Default",
3014− "labels": [
3015− "self-hosted",
3016− "linux",
3017− "x64",
3018− "gpu"
3019− ],
3020− "os": "linux",
3021− "arch": "x64",
3022− "version": "0.2.0",
3023− "ephemeral": false,
3024− "status": "busy",
3025− "work": {
3026− "kind": "workflow",
3027− "id": "job_01kq2m9b1d4g7j0m3p6s9v2y5b",
3028− "name": "test (linux, 24)",
3029− "repo": "flagon-io/hello",
3030− "run_id": "run_01kq2m9a8c1f4h7k0n3q6t9w2z",
3031− "started_at": "2026-10-06T14:02:11.000Z"
3032− },
3033− "last_seen_at": "2026-10-06T14:05:40.512Z",
3034− "created_at": "2026-10-02T09:30:00.000Z",
3035− "created_by": null
3036− },
3037− {
3038− "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w9a",
3039− "name": "mac-mini",
3040− "workspace": "flagon-io",
3041− "repo": null,
3042− "group": "Default",
3043− "labels": [
3044− "self-hosted",
3045− "macos",
3046− "arm64"
3047− ],
3048− "os": "macos",
3049− "arch": "arm64",
3050− "version": "0.2.0",
3051− "ephemeral": false,
3052− "status": "online",
3053− "work": null,
3054− "last_seen_at": "2026-10-06T14:05:40.512Z",
3055− "created_at": "2026-10-02T09:30:00.000Z",
3056− "created_by": null
3057− }
3058− ],
3059− "notes": "A repository's list holds its own runners (`repo` set) and the workspace's that its runner group lets it use. A runner is `offline` when it has not polled for 90 seconds."
3060− },
3061− "list_runners_for_workspace": {
3062− "params": {
3063− "workspace": "flagon-io"
3064− },
3065− "response": [
3066− {
3067− "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z",
3068− "name": "build-01",
3069− "workspace": "flagon-io",
3070− "repo": null,
3071− "group": "Default",
3072− "labels": [
3073− "self-hosted",
3074− "linux",
3075− "x64",
3076− "gpu"
3077− ],
3078− "os": "linux",
3079− "arch": "x64",
3080− "version": "0.2.0",
3081− "ephemeral": false,
3082− "status": "busy",
3083− "work": {
3084− "kind": "workflow",
3085− "id": "job_01kq2m9b1d4g7j0m3p6s9v2y5b",
3086− "name": "test (linux, 24)",
3087− "repo": "flagon-io/hello",
3088− "run_id": "run_01kq2m9a8c1f4h7k0n3q6t9w2z",
3089− "started_at": "2026-10-06T14:02:11.000Z"
3090− },
3091− "last_seen_at": "2026-10-06T14:05:40.512Z",
3092− "created_at": "2026-10-02T09:30:00.000Z",
3093− "created_by": null
3094− },
3095− {
3096− "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w9a",
3097− "name": "mac-mini",
3098− "workspace": "flagon-io",
3099− "repo": null,
3100− "group": "Default",
3101− "labels": [
3102− "self-hosted",
3103− "macos",
3104− "arm64"
3105− ],
3106− "os": "macos",
3107− "arch": "arm64",
3108− "version": "0.2.0",
3109− "ephemeral": false,
3110− "status": "online",
3111− "work": null,
3112− "last_seen_at": "2026-10-06T14:05:40.512Z",
3113− "created_at": "2026-10-02T09:30:00.000Z",
3114− "created_by": null
3115− }
3116− ]
3117− },
3118− "create_runner_registration_token": {
3119− "response": {
3120− "token": "g1trt_…",
3121− "expires_at": "2026-10-06T15:04:00.000Z",
3122− "workspace": "flagon-io",
3123− "repo": "flagon-io/hello",
3124− "group": null,
3125− "url": "https://g1t.sh"
3126− },
3127− "notes": "Pass it to `g1t-runner register --url https://g1t.sh --token …` within the hour. See [self-hosted runners](/guides/self-hosted-runners/)."
3128− },
3129− "create_runner_registration_token_for_workspace": {
3130− "params": {
3131− "workspace": "flagon-io"
3132− },
3133− "request": {
3134− "group": "Default"
3135− },
3136− "response": {
3137− "token": "g1trt_…",
3138− "expires_at": "2026-10-06T15:04:00.000Z",
3139− "workspace": "flagon-io",
3140− "repo": null,
3141− "group": "Default",
3142− "url": "https://g1t.sh"
3143− }
3144− },
3145− "remove_runner": {
3146− "params": {
3147− "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z"
3148− },
3149− "response": true
3150− },
3151− "remove_runner_for_workspace": {
3152− "params": {
3153− "workspace": "flagon-io",
3154− "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z"
3155− },
3156− "response": true
3157− },
3158− "get_runner_settings": {
3159− "response": {
3160− "agents_on_self_hosted": false,
3161− "agent_labels": [
3162− "self-hosted",
3163− "linux"
3164− ],
3165− "fork_pull_requests": false,
3166− "inherited": true
3167− }
3168− },
3169− "get_runner_settings_for_workspace": {
3170− "params": {
3171− "workspace": "flagon-io"
3172− },
3173− "response": {
3174− "agents_on_self_hosted": true,
3175− "agent_labels": [
3176− "self-hosted",
3177− "linux"
3178− ],
3179− "fork_pull_requests": false,
3180− "inherited": false
3181− }
3182− },
3183− "update_runner_settings": {
3184− "request": {
3185− "inherit": true
3186− },
3187− "response": {
3188− "agents_on_self_hosted": false,
3189− "agent_labels": [
3190− "self-hosted",
3191− "linux"
3192− ],
3193− "fork_pull_requests": false,
3194− "inherited": true
3195− }
3196− },
3197− "update_runner_settings_for_workspace": {
3198− "params": {
3199− "workspace": "flagon-io"
3200− },
3201− "request": {
3202− "agents_on_self_hosted": true,
3203− "agent_labels": [
3204− "linux"
3205− ]
3206− },
3207− "response": {
3208− "agents_on_self_hosted": true,
3209− "agent_labels": [
3210− "self-hosted",
3211− "linux"
3212− ],
3213− "fork_pull_requests": false,
3214− "inherited": false
3215− },
3216− "notes": "Agent work on your runners still uses g1t's model proxy, paid as before, unless the workspace has its own model provider."
3217− },
3218− "list_runner_groups": {
3219− "params": {
3220− "workspace": "flagon-io"
3221− },
3222− "response": [
3223− {
3224− "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6y",
3225− "name": "Default",
3226− "default": true,
3227− "repositories": [],
3228− "runners": 2,
3229− "updated_at": "2026-10-02T09:30:00.000Z"
3230− },
3231− {
3232− "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z",
3233− "name": "GPU",
3234− "default": false,
3235− "repositories": [
3236− "hello",
3237− "models"
3238− ],
3239− "runners": 1,
3240− "updated_at": "2026-10-05T11:20:00.000Z"
3241− }
3242− ]
3243− },
3244− "create_runner_group": {
3245− "params": {
3246− "workspace": "flagon-io"
3247− },
3248− "request": {
3249− "name": "GPU",
3250− "repositories": [
3251− "hello",
3252− "models"
3253− ]
3254− },
3255− "response": {
3256− "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z",
3257− "name": "GPU",
3258− "default": false,
3259− "repositories": [
3260− "hello",
3261− "models"
3262− ],
3263− "runners": 1,
3264− "updated_at": "2026-10-05T11:20:00.000Z"
3265− }
3266− },
3267− "update_runner_group": {
3268− "params": {
3269− "workspace": "flagon-io",
3270− "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z"
3271− },
3272− "request": {
3273− "repositories": []
3274− },
3275− "response": {
3276− "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z",
3277− "name": "GPU",
3278− "default": false,
3279− "repositories": [],
3280− "runners": 1,
3281− "updated_at": "2026-10-05T11:20:00.000Z"
3282− }
3283− },
3284− "delete_runner_group": {
3285− "params": {
3286− "workspace": "flagon-io",
3287− "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z"
3288− },
3289− "response": true
3290− },
3291− "list_webhooks": {
3292− "response": [
3293− {
3294− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3295− "scope": "repo",
3296− "workspace": "flagon-io",
3297− "repo": "flagon-io/hello",
3298− "url": "https://hooks.example.com/g1t",
3299− "events": [
3300− "git.push",
3301− "pull.merged"
3302− ],
3303− "active": true,
3304− "secret_hint": "…9c2e",
3305− "created_by": "syntaqx",
3306− "created_at": "2026-10-04T15:42:07.318Z",
3307− "last_status": "delivered",
3308− "last_delivered_at": "2026-10-04T15:42:07.611Z"
3309− }
3310− ]
3311− },
3312− "list_webhooks_for_workspace": {
3313− "params": {
3314− "workspace": "flagon-io"
3315− },
3316− "response": [
3317− {
3318− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3319− "scope": "workspace",
3320− "workspace": "flagon-io",
3321− "repo": null,
3322− "url": "https://hooks.example.com/g1t",
3323− "events": [
3324− "git.push",
3325− "pull.merged"
3326− ],
3327− "active": true,
3328− "secret_hint": "…9c2e",
3329− "created_by": "syntaqx",
3330− "created_at": "2026-10-04T15:42:07.318Z",
3331− "last_status": "delivered",
3332− "last_delivered_at": "2026-10-04T15:42:07.611Z"
3333− }
3334− ]
3335− },
3336− "create_webhook": {
3337− "request": {
3338− "url": "https://hooks.example.com/g1t",
3339− "events": [
3340− "git.push",
3341− "pull.merged"
3342− ]
3343− },
3344− "response": {
3345− "hook": {
3346− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3347− "scope": "repo",
3348− "workspace": "flagon-io",
3349− "repo": "flagon-io/hello",
3350− "url": "https://hooks.example.com/g1t",
3351− "events": [
3352− "git.push",
3353− "pull.merged"
3354− ],
3355− "active": true,
3356− "secret_hint": "…9c2e",
3357− "created_by": "syntaqx",
3358− "created_at": "2026-10-04T15:42:07.318Z",
3359− "last_status": "delivered",
3360− "last_delivered_at": "2026-10-04T15:42:07.611Z"
3361− },
3362− "secret": "whsec_…"
3363− },
3364− "notes": "A ping is sent before the response, so `last_status` is usually set already. When g1t made the signing secret, `secret` holds it: it is shown only this once. See [webhooks](/guides/webhooks/)."
3365− },
3366− "create_webhook_for_workspace": {
3367− "params": {
3368− "workspace": "flagon-io"
3369− },
3370− "request": {
3371− "url": "https://hooks.example.com/g1t"
3372− },
3373− "response": {
3374− "hook": {
3375− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3376− "scope": "workspace",
3377− "workspace": "flagon-io",
3378− "repo": null,
3379− "url": "https://hooks.example.com/g1t",
3380− "events": [
3381− "*"
3382− ],
3383− "active": true,
3384− "secret_hint": "…9c2e",
3385− "created_by": "syntaqx",
3386− "created_at": "2026-10-04T15:42:07.318Z",
3387− "last_status": "delivered",
3388− "last_delivered_at": "2026-10-04T15:42:07.611Z"
3389− },
3390− "secret": "whsec_…"
3391− },
3392− "notes": "A ping is sent before the response, so `last_status` is usually set already. When g1t made the signing secret, `secret` holds it: it is shown only this once. See [webhooks](/guides/webhooks/)."
3393− },
3394− "update_webhook": {
3395− "params": {
3396− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3397− },
3398− "request": {
3399− "active": false
3400− },
3401− "response": {
3402− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3403− "scope": "repo",
3404− "workspace": "flagon-io",
3405− "repo": "flagon-io/hello",
3406− "url": "https://hooks.example.com/g1t",
3407− "events": [
3408− "git.push",
3409− "pull.merged"
3410− ],
3411− "active": false,
3412− "secret_hint": "…9c2e",
3413− "created_by": "syntaqx",
3414− "created_at": "2026-10-04T15:42:07.318Z",
3415− "last_status": "delivered",
3416− "last_delivered_at": "2026-10-04T15:42:07.611Z"
3417− }
3418− },
3419− "update_webhook_for_workspace": {
3420− "params": {
3421− "workspace": "flagon-io",
3422− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3423− },
3424− "request": {
3425− "active": false
3426− },
3427− "response": {
3428− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3429− "scope": "workspace",
3430− "workspace": "flagon-io",
3431− "repo": null,
3432− "url": "https://hooks.example.com/g1t",
3433− "events": [
3434− "git.push",
3435− "pull.merged"
3436− ],
3437− "active": false,
3438− "secret_hint": "…9c2e",
3439− "created_by": "syntaqx",
3440− "created_at": "2026-10-04T15:42:07.318Z",
3441− "last_status": "delivered",
3442− "last_delivered_at": "2026-10-04T15:42:07.611Z"
3443− }
3444− },
3445− "delete_webhook": {
3446− "params": {
3447− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3448− },
3449− "response": true
3450− },
3451− "delete_webhook_for_workspace": {
3452− "params": {
3453− "workspace": "flagon-io",
3454− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3455− },
3456− "response": true
3457− },
3458− "ping_webhook": {
3459− "params": {
3460− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3461− },
3462− "response": {
3463− "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3464− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3465− "event_id": "",
3466− "event": "ping",
3467− "status": "delivered",
3468− "attempts": 1,
3469− "response_status": 200,
3470− "response_body": "ok",
3471− "error": null,
3472− "duration_ms": 184,
3473− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3474− "created_at": "2026-10-04T16:01:12.440Z",
3475− "delivered_at": "2026-10-04T16:01:12.631Z",
3476− "next_attempt_at": null
3477− },
3478− "notes": "`payload` is the JSON that was sent, as a string."
3479− },
3480− "ping_webhook_for_workspace": {
3481− "params": {
3482− "workspace": "flagon-io",
3483− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3484− },
3485− "response": {
3486− "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3487− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3488− "event_id": "",
3489− "event": "ping",
3490− "status": "delivered",
3491− "attempts": 1,
3492− "response_status": 200,
3493− "response_body": "ok",
3494− "error": null,
3495− "duration_ms": 184,
3496− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3497− "created_at": "2026-10-04T16:01:12.440Z",
3498− "delivered_at": "2026-10-04T16:01:12.631Z",
3499− "next_attempt_at": null
3500− }
3501− },
3502− "list_webhook_deliveries": {
3503− "params": {
3504− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3505− },
3506− "response": [
3507− {
3508− "id": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz",
3509− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3510− "event_id": "",
3511− "event": "ping",
3512− "status": "pending",
3513− "attempts": 1,
3514− "response_status": 503,
3515− "response_body": "Service Unavailable",
3516− "error": null,
3517− "duration_ms": 212,
3518− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3519− "created_at": "2026-10-04T16:20:03.100Z",
3520− "delivered_at": null,
3521− "next_attempt_at": "2026-10-04T16:21:03.312Z"
3522− },
3523− {
3524− "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3525− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3526− "event_id": "",
3527− "event": "ping",
3528− "status": "delivered",
3529− "attempts": 1,
3530− "response_status": 200,
3531− "response_body": "ok",
3532− "error": null,
3533− "duration_ms": 184,
3534− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3535− "created_at": "2026-10-04T16:01:12.440Z",
3536− "delivered_at": "2026-10-04T16:01:12.631Z",
3537− "next_attempt_at": null
3538− }
3539− ],
3540− "notes": "Returns at most 50, newest first. `status` is `pending`, `delivered` or `failed`; `next_attempt_at` is set while it is pending."
3541− },
3542− "list_webhook_deliveries_for_workspace": {
3543− "params": {
3544− "workspace": "flagon-io",
3545− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3546− },
3547− "response": [
3548− {
3549− "id": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz",
3550− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3551− "event_id": "",
3552− "event": "ping",
3553− "status": "pending",
3554− "attempts": 1,
3555− "response_status": 503,
3556− "response_body": "Service Unavailable",
3557− "error": null,
3558− "duration_ms": 212,
3559− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3560− "created_at": "2026-10-04T16:20:03.100Z",
3561− "delivered_at": null,
3562− "next_attempt_at": "2026-10-04T16:21:03.312Z"
3563− },
3564− {
3565− "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3566− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3567− "event_id": "",
3568− "event": "ping",
3569− "status": "delivered",
3570− "attempts": 1,
3571− "response_status": 200,
3572− "response_body": "ok",
3573− "error": null,
3574− "duration_ms": 184,
3575− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3576− "created_at": "2026-10-04T16:01:12.440Z",
3577− "delivered_at": "2026-10-04T16:01:12.631Z",
3578− "next_attempt_at": null
3579− }
3580− ]
3581− },
3582− "redeliver_webhook": {
3583− "params": {
3584− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3585− "delivery": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz"
3586− },
3587− "response": {
3588− "id": "dlv_01kpx6c8d1e2f3g4h5j6k7m8np",
3589− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3590− "event_id": "",
3591− "event": "ping",
3592− "status": "delivered",
3593− "attempts": 1,
3594− "response_status": 200,
3595− "response_body": "ok",
3596− "error": null,
3597− "duration_ms": 171,
3598− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3599− "created_at": "2026-10-04T16:25:40.007Z",
3600− "delivered_at": "2026-10-04T16:25:40.178Z",
3601− "next_attempt_at": null
3602− },
3603− "notes": "The response is the new delivery."
3604− },
3605− "redeliver_webhook_for_workspace": {
3606− "params": {
3607− "workspace": "flagon-io",
3608− "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3609− "delivery": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz"
3610− },
3611− "response": {
3612− "id": "dlv_01kpx6c8d1e2f3g4h5j6k7m8np",
3613− "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3614− "event_id": "",
3615− "event": "ping",
3616− "status": "delivered",
3617− "attempts": 1,
3618− "response_status": 200,
3619− "response_body": "ok",
3620− "error": null,
3621− "duration_ms": 171,
3622− "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3623− "created_at": "2026-10-04T16:25:40.007Z",
3624− "delivered_at": "2026-10-04T16:25:40.178Z",
3625− "next_attempt_at": null
3626− }
3627− },
3628− "list_integrations": {
3629− "params": {
3630− "workspace": "flagon-io"
3631− },
3632− "response": [
3633− {
3634− "id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3635− "workspace": "flagon-io",
3636− "provider": "anthropic",
3637− "kind": "models",
3638− "name": "Anthropic",
3639− "config": {
3640− "assign": false,
3641− "write_back": true
3642− },
3643− "secret_hint": "…3f9a",
3644− "webhook_url": null,
3645− "created_by": "syntaqx",
3646− "created_at": "2026-10-04T15:42:07.318Z",
3647− "last_used_at": "2026-10-04T15:42:08.102Z",
3648− "last_error": null,
3649− "models": [
3650− "claude-haiku-4-5",
3651− "claude-sonnet-4-5"
3652− ]
3653− },
3654− {
3655− "id": "con_01kpx4n8r3g9s0v5w7x1z2a3bc",
3656− "workspace": "flagon-io",
3657− "provider": "jira",
3658− "kind": "tracker",
3659− "name": "Jira",
3660− "config": {
3661− "assign": false,
3662− "write_back": true,
3663− "site": "https://acme.atlassian.net",
3664− "email": "syntaqx@example.com",
3665− "keys": [
3666− "TECH"
3667− ]
3668− },
3669− "secret_hint": "…x7Qe",
3670− "webhook_url": null,
3671− "created_by": "syntaqx",
3672− "created_at": "2026-10-04T15:42:07.318Z",
3673− "last_used_at": null,
3674− "last_error": null,
3675− "models": []
3676− }
3677− ],
3678− "notes": "`kind` is `models`, `alerts` or `tracker`. `secret_hint` shows the end of the secret; the secret itself is never returned. `webhook_url` is where an alert source sends its alerts."
3679− },
3680− "connect_integration": {
3681− "params": {
3682− "workspace": "flagon-io"
3683− },
3684− "request": {
3685− "provider": "webhook",
3686− "config": {
3687− "repo": "flagon-io/hello",
3688− "label": "bug"
3689− }
3690− },
3691− "response": {
3692− "connection": {
3693− "id": "con_01kpx4n8r3g9s0v5w7x1z2a3bd",
3694− "workspace": "flagon-io",
3695− "provider": "webhook",
3696− "kind": "alerts",
3697− "name": "Webhook",
3698− "config": {
3699− "repo": "flagon-io/hello",
3700− "label": "bug",
3701− "assign": false,
3702− "write_back": true
3703− },
3704− "secret_hint": null,
3705− "webhook_url": "https://api.g1t.sh/hooks/con_01kpx4n8r3g9s0v5w7x1z2a3bd",
3706− "created_by": "syntaqx",
3707− "created_at": "2026-10-04T15:42:07.318Z",
3708− "last_used_at": null,
3709− "last_error": null,
3710− "models": []
3711− },
3712− "signing_secret": "g1ts_9f2c4a7e1b0d3c6f8a2e5b7d9c1f4a6e8b0d2c4f6a8e1b3d"
3713− },
3714− "notes": "`signing_secret` is set only when g1t made it, for `datadog` and `webhook`, and is shown only this once. A model provider is tested as it is connected. See [integrations](/guides/integrations/) and [model providers](/guides/models/)."
3715− },
3716− "disconnect_integration": {
3717− "params": {
3718− "workspace": "flagon-io",
3719− "id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab"
3720− },
3721− "response": true
3722− },
3723− "test_integration": {
3724− "params": {
3725− "workspace": "flagon-io",
3726− "id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab"
3727− },
3728− "response": {
3729− "ok": true,
3730− "message": "Anthropic accepted the key and offers 9 models."
3731− },
3732− "notes": "Credentials that do not work still answer `200`, with `ok` false and `message` saying what went wrong."
3733− },
3734− "get_model_routes": {
3735− "params": {
3736− "workspace": "flagon-io"
3737− },
3738− "response": [
3739− {
3740− "task": "default",
3741− "connection_id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3742− "model": "claude-sonnet-4-5"
3743− },
3744− {
3745− "task": "review",
3746− "connection_id": null,
3747− "model": null
3748− }
3749− ]
3750− },
3751− "set_model_routes": {
3752− "params": {
3753− "workspace": "flagon-io"
3754− },
3755− "request": {
3756− "routes": [
3757− {
3758− "task": "default",
3759− "connection_id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3760− "model": "claude-sonnet-4-5"
3761− },
3762− {
3763− "task": "plan",
3764− "connection_id": null,
3765− "model": "frontier"
3766− },
3767− {
3768− "task": "review",
3769− "connection_id": null
3770− }
3771− ]
3772− },
3773− "response": [
3774− {
3775− "task": "default",
3776− "connection_id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3777− "model": "claude-sonnet-4-5"
3778− },
3779− {
3780− "task": "plan",
3781− "connection_id": null,
3782− "model": "frontier"
3783− },
3784− {
3785− "task": "review",
3786− "connection_id": null,
3787− "model": null
3788− }
3789− ],
3790− "notes": "The response is the routes as saved, ordered by task. On g1t's hosted models (`connection_id` null), `model` is `small`, `large` or `frontier`, or null for Auto, which picks the cheapest model that can do each job and says why on the run."
3791− },
3792− "get_context": {
3793− "query": {
3794− "reference": "TECH-1234"
3795− },
3796− "response": {
3797− "provider": "jira",
3798− "key": "TECH-1234",
3799− "title": "Checkout fails for EU cards",
3800− "url": "https://acme.atlassian.net/browse/TECH-1234",
3801− "status": "In Progress",
3802− "body": "Customers with 3DS cards see a 500 at /pay.",
3803− "fetched_at": "2026-10-04T15:42:07.318Z"
3804− }
3805− },
3806− "import_issue": {
3807− "request": {
3808− "reference": "TECH-1234"
3809− },
3810− "response": {
3811− "number": 42,
3812− "item": {
3813− "provider": "jira",
3814− "key": "TECH-1234",
3815− "title": "Checkout fails for EU cards",
3816− "url": "https://acme.atlassian.net/browse/TECH-1234",
3817− "status": "In Progress",
3818− "body": "Customers with 3DS cards see a 500 at /pay.",
3819− "fetched_at": "2026-10-04T15:42:07.318Z"
3820− },
3821− "created": true
3822− },
3823− "notes": "`created` is false when the ticket was imported before; `number` is then that issue."
3824− },
3825− "remember": {
3826− "request": {
3827− "text": "The tests need TZ=UTC or the date tests fail.",
3828− "scope": "project",
3829− "kind": "gotcha",
3830− "from_number": 14
3831− },
3832− "response": {
3833− "id": "mem_01m43v8q2w3e4r5t6y7u8i9o0p",
3834− "scope": "project",
3835− "workspace": "flagon-io",
3836− "repo": {
3837− "namespace": "flagon-io",
3838− "name": "hello"
3839− },
3840− "text": "The tests need TZ=UTC or the date tests fail.",
3841− "kind": "gotcha",
3842− "source": {
3843− "kind": "run",
3844− "run_id": "arn_01m43v2c1p9k8d7e6f5a4b3c2d",
3845− "repo": {
3846− "namespace": "flagon-io",
3847− "name": "hello"
3848− },
3849− "number": 14
3850− },
3851− "created_by": "g1t",
3852− "pinned": false,
3853− "created_at": "2026-10-01T18:40:12.000Z",
3854− "updated_at": "2026-10-01T18:40:12.000Z",
3855− "last_used_at": null
3856− },
3857− "notes": "Text that looks like a key, a token or a password is refused with `invalid`: memory is read by every agent in the workspace. Saving the same text again in the same scope returns the memory already kept."
3858− },
3859− "recall": {
3860− "query": {
3861− "q": "pnpm"
3862− },
3863− "response": {
3864− "project": [],
3865− "workspace": [
3866− {
3867− "id": "mem_01m43t0a1s2d3f4g5h6j7k8l9z",
3868− "scope": "workspace",
3869− "workspace": "flagon-io",
3870− "repo": null,
3871− "text": "We use pnpm everywhere, never npm or yarn.",
3872− "kind": "convention",
3873− "source": {
3874− "kind": "person",
3875− "run_id": null,
3876− "repo": null,
3877− "number": null
3878− },
3879− "created_by": "syntaqx",
3880− "pinned": true,
3881− "created_at": "2026-10-01T18:40:12.000Z",
3882− "updated_at": "2026-10-01T18:40:12.000Z",
3883− "last_used_at": null
3884− }
3885− ]
3886− },
3887− "notes": "Anyone who can read the repository gets its project memory; `workspace` is filled only for members of the workspace, and is empty for anyone else. Each memory returned is marked used, which keeps it near the front of what agents are given."
3888− },
3889− "search": {
3890− "query": {
3891− "q": "parse_query language:rust repo:acme/web",
3892− "type": "code"
3893− },
3894− "response": {
3895− "query": "parse_query repo:acme/web language:rust",
3896− "type": "code",
3897− "counts": {
3898− "repositories": 0,
3899− "code": 2,
3900− "issues": 0,
3901− "pulls": 0,
3902− "people": 0
3903− },
3904− "page": 1,
3905− "per_page": 20,
3906− "more": false,
3907− "hits": [
3908− {
3909− "kind": "code",
3910− "title": "src/search/query.rs",
3911− "url": "/acme/web/blob/main/src/search/query.rs#L42",
3912− "repo": "acme/web",
3913− "private": false,
3914− "description": null,
3915− "snippet": [],
3916− "lines": [
3917− {
3918− "number": 41,
3919− "parts": [
3920− {
3921− "text": "/// Reads a query typed into the search box.",
3922− "highlight": false
3923− }
3924− ]
3925− },
3926− {
3927− "number": 42,
3928− "parts": [
3929− {
3930− "text": "pub fn ",
3931− "highlight": false
3932− },
3933− {
3934− "text": "parse_query",
3935− "highlight": true
3936− },
3937− {
3938− "text": "(text: &str) -> Query {",
3939− "highlight": false
3940− }
3941− ]
3942− },
3943− {
3944− "number": 43,
3945− "parts": [
3946− {
3947− "text": " let mut query = Query::default();",
3948− "highlight": false
3949− }
3950− ]
3951− }
3952− ],
3953− "path": "src/search/query.rs",
3954− "language": "rust",
3955− "ref": "main",
3956− "number": null,
3957− "state": null,
3958− "author": null,
3959− "requested_by": null,
3960− "labels": [],
3961− "topics": [],
3962− "slug": null,
3963− "avatar": null,
3964− "updated_at": null
3965− }
3966− ],
3967− "notes": []
3968− },
3969− "notes": "`q` takes words, `\"exact phrases\"`, `-words` to leave out, and qualifiers: `repo:owner/name`, `org:` (or `workspace:`), `language:`, `path:` (a glob when it has `*`), `is:issue`, `is:pr`, `is:open`, `is:closed`, `is:merged`, `is:draft`, `is:public`, `is:private`, `author:` and `label:`; most can be left out with a leading `-`, as in `-label:wontfix`. `type` is `repositories`, `code`, `issues`, `pulls` or `people`; without it, `path:` means code, `is:pr` pull requests, `is:open`, `author:` or `label:` issues, and anything else repositories. `counts` says how many results each type has, up to 1,000. Each result's `snippet` (or, for code, each of its `lines`) is a list of parts, `highlight` true where the query matched. Code is searched on default branches and needs a word of three characters or more, unless the query names a `repo:`. Public content is returned to anyone, without a token; private content only to people who can read it (members of its workspace, and people given a role on the repository), checked when the search runs, so a repository made private, or a role taken away, stops appearing at once. A g1t agent's token can search too. An issue or pull request g1t opened has `author` `g1t` and `requested_by` the person it was for; `author:` matches the author."
3970− },
3971− "search_context": {
3972− "params": {
3973− "workspace": "acme"
3974− },
3975− "query": {
3976− "q": "how do we run the web tests",
3977− "project": "web"
3978− },
3979− "response": {
3980− "query": "how do we run the web tests",
3981− "mode": "semantic",
3982− "hits": [
3983− {
3984− "kind": "memory",
3985− "id": "mem_01m4a0c2b7k3f9d1e5g8h2j6k4",
3986− "title": "Gotcha",
3987− "snippet": "The date tests fail unless TZ=UTC.",
3988− "project": "web",
3989− "url": "/acme/web/memory",
3990− "score": 0.82,
3991− "source": "AGENTS.md",
3992− "by": "g1t",
3993− "updated_at": "2026-10-04T21:10:02.000Z"
3994− },
3995− {
3996− "kind": "doc",
3997− "id": "ent_5f0c2a9e41d7b3c86a1e2f40:2",
3998− "title": "Web (README.md)",
3999− "snippet": "## Testing Run npm test. The end-to-end tests need the api running locally…",
4000− "project": "web",
4001− "url": "/acme/web/blob/main/README.md",
4002− "score": 0.77,
4003− "source": "README.md",
4004− "by": null,
4005− "updated_at": "2026-10-04T20:58:41.000Z"
4006− },
4007− {
4008− "kind": "project",
4009− "id": "ent_9b1d6f0a2c3e4b5d6e7f8a9b",
4010− "title": "web",
4011− "snippet": "The storefront. Written in TypeScript. Packages: @acme/web. Uses api. Owned by ana.",
4012− "project": "web",
4013− "url": "/acme/web",
4014− "score": 0.71,
4015− "source": "catalog",
4016− "by": null,
4017− "updated_at": "2026-10-04T20:58:41.000Z"
4018− }
4019− ]
4020− },
4021− "notes": "Give `workspace`, or `repo` as `owner/name` for its workspace. `kinds` narrows to some of `project`, `app`, `api`, `package`, `language`, `owner`, `environment`, `integration`, `doc`, `memory`, `issue` and `pull`; in a URL, comma-separated. `mode` is `text` when the search index could not answer and words were matched instead. Memory is returned only to members of the workspace and its agents; anything from a private project, only to those who can read it (members, unless the base permission is None, and people given a role on its repository). A g1t agent searches its own workspace only."
4022− },
4023− "get_entity": {
4024− "params": {
4025− "workspace": "acme",
4026− "kind": "project",
4027− "id": "web"
4028− },
4029− "response": {
4030− "entity": {
4031− "id": "ent_9b1d6f0a2c3e4b5d6e7f8a9b",
4032− "workspace": "acme",
4033− "kind": "project",
4034− "key": "web",
4035− "name": "web",
4036− "summary": "The storefront. Written in TypeScript. Packages: @acme/web. Uses api. Owned by ana.",
4037− "project": "web",
4038− "private": true,
4039− "data": {
4040− "repo": "acme/web",
4041− "root_dir": "",
4042− "default_branch": "main",
4043− "languages": [
4044− "TypeScript"
4045− ],
4046− "owners": [
4047− "ana"
4048− ],
4049− "tests": true,
4050− "test_commands": [
4051− "npm test"
4052− ],
4053− "production_url": "https://web--acme.g1t.page"
4054− },
4055− "source": "scan",
4056− "ref": "/acme/web",
4057− "updated_at": "2026-10-04T20:58:41.000Z"
4058− },
4059− "relations": [
4060− {
4061− "kind": "depends_on",
4062− "direction": "out",
4063− "entity": {
4064− "id": "ent_0a7c3e5b9d1f2a4c6e8b0d2f",
4065− "workspace": "acme",
4066− "kind": "project",
4067− "key": "api",
4068− "name": "api",
4069− "summary": "The public API. Written in Rust.",
4070− "project": "api",
4071− "private": true,
4072− "data": {},
4073− "source": "scan",
4074− "ref": "/acme/api",
4075− "updated_at": "2026-10-04T20:57:12.000Z"
4076− }
4077− },
4078− {
4079− "kind": "owned_by",
4080− "direction": "out",
4081− "entity": {
4082− "id": "ent_3c5e7a9b1d2f4a6c8e0b2d4f",
4083− "workspace": "acme",
4084− "kind": "owner",
4085− "key": "ana",
4086− "name": "ana",
4087− "summary": null,
4088− "project": null,
4089− "private": false,
4090− "data": {},
4091− "source": "scan",
4092− "ref": "/u/ana",
4093− "updated_at": "2026-10-04T20:58:41.000Z"
4094− }
4095− }
4096− ]
4097− },
4098− "notes": "`id` is the entry's id, or its key: a project's or app's slug, `npm:<name>` (or `cargo:`, `go:`, `pypi:`) for a package, a username for an owner, `<project>/production` for an environment. `data` depends on the kind: a package's version and dependencies, an API's routes, an app's production address."
4099− },
4100− "list_collaborators": {
4101− "response": {
4102− "repo": "flagon-io/hello",
4103− "base_permission": "write",
4104− "people": [
4105− {
4106− "username": "syntaqx",
4107− "name": "Chase Pierce",
4108− "avatar": null,
4109− "role": "admin",
4110− "source": "owner",
4111− "direct": null,
4112− "workspace_role": "owner"
4113− },
4114− {
4115− "username": "linus",
4116− "name": null,
4117− "avatar": null,
4118− "role": "maintain",
4119− "source": "direct",
4120− "direct": "maintain",
4121− "workspace_role": "member"
4122− },
4123− {
4124− "username": "grace",
4125− "name": "Grace Hopper",
4126− "avatar": null,
4127− "role": "write",
4128− "source": "base",
4129− "direct": null,
4130− "workspace_role": "member"
4131− },
4132− {
4133− "username": "ada",
4134− "name": "Ada Lovelace",
4135− "avatar": null,
4136− "role": "triage",
4137− "source": "direct",
4138− "direct": "triage",
4139− "workspace_role": null
4140− }
4141− ],
4142− "invitations": [
4143− {
4144− "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p",
4145− "repo": "flagon-io/hello",
4146− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4147− "invitee": "alan",
4148− "email": null,
4149− "role": "write",
4150− "invited_by": "syntaqx",
4151− "inviter_avatar": null,
4152− "status": "pending",
4153− "created_at": "2026-10-05T17:00:00.000Z",
4154− "expires_at": "2026-10-12T17:00:00.000Z"
4155− },
4156− {
4157− "id": "rin_01kp3d7e8f9g0h1j2k3m4n5p6q",
4158− "repo": "flagon-io/hello",
4159− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4160− "invitee": null,
4161− "email": "joan@example.com",
4162− "role": "read",
4163− "invited_by": "syntaqx",
4164− "inviter_avatar": null,
4165− "status": "pending",
4166− "created_at": "2026-10-05T17:00:00.000Z",
4167− "expires_at": "2026-10-12T17:00:00.000Z"
4168− }
4169− ],
4170− "viewer_role": "admin",
4171− "can_manage": true
4172− },
4173− "notes": "Owners are listed with `source` `owner`, members with the base permission with `base`, and anyone given a role on this repository with `direct`; `role` is the highest of these, and `direct` shows a direct role even when ownership or the base permission gives more. `workspace_role` null means an outside collaborator. Anyone can read a public repository, which is not listed. `invitations` is empty unless you have the Admin role (`can_manage`). Refused with `403` below the Write role, and `404` for a private repository you cannot see. See [Access and roles](/guides/access-and-roles/)."
4174− },
4175− "add_collaborator": {
4176− "request": {
4177− "invitee": "ada",
4178− "role": "triage"
4179− },
4180− "response": {
4181− "result": "invited",
4182− "invitation": {
4183− "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4184− "repo": "flagon-io/hello",
4185− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4186− "invitee": "ada",
4187− "email": null,
4188− "role": "triage",
4189− "invited_by": "syntaqx",
4190− "inviter_avatar": null,
4191− "status": "pending",
4192− "created_at": "2026-10-05T17:00:00.000Z",
4193− "expires_at": "2026-10-12T17:00:00.000Z"
4194− }
4195− },
4196− "notes": "`invitee` is a username or an email address. A member of the workspace answers `{\"result\": \"granted\", \"collaborator\": {…}}` with the role already given, shown as list_collaborators shows a person. Anyone else answers `{\"result\": \"invited\", \"invitation\": {…}}`: the invitation is emailed and waits 7 days, and the role is theirs once they accept it. An email address without an account gets an invitation with `email` set and `invitee` null, and an invite that makes the account and accepts in one step. Refused with `404` when no account has that username, `409` when they already have a role of their own or a pending invitation (change it with update_collaborator), and `403` without the Admin role, from an agent's or a workspace's token, or when the person does not meet what the workspace asks of everyone with access. The `repo.collaborator_added` webhook event is sent once they have the role. See [Access and roles](/guides/access-and-roles/)."
4197− },
4198− "update_collaborator": {
4199− "params": {
4200− "owner": "flagon-io",
4201− "name": "hello",
4202− "username": "ada"
4203− },
4204− "request": {
4205− "role": "write"
4206− },
4207− "response": {
4208− "username": "ada",
4209− "name": "Ada Lovelace",
4210− "avatar": null,
4211− "role": "write",
4212− "source": "direct",
4213− "direct": "write",
4214− "workspace_role": null
4215− },
4216− "notes": "Changes a direct role, or the role of the person's pending invitation. `404` when they have neither: an owner's Admin and a member's base permission are not changed here. Changing a direct role sends the `repo.collaborator_role_changed` webhook event. See [Access and roles](/guides/access-and-roles/)."
4217− },
4218− "remove_collaborator": {
4219− "params": {
4220− "owner": "flagon-io",
4221− "name": "hello",
4222− "username": "ada"
4223− },
4224− "response": true,
4225− "notes": "Takes away a direct role. Anyone may remove their own, to leave a repository. `404` when the person has no role of their own on it. A member keeps the workspace's base permission. Sends the `repo.collaborator_removed` webhook event. See [Access and roles](/guides/access-and-roles/)."
4226− },
4227− "get_collaborator_permission": {
4228− "params": {
4229− "owner": "flagon-io",
4230− "name": "hello",
4231− "username": "ada"
4232− },
4233− "response": {
4234− "username": "ada",
4235− "role": "triage",
4236− "source": "direct",
4237− "capabilities": [
4238− "read",
4239− "participate",
4240− "triage"
4241− ]
4242− },
4243− "notes": "`capabilities` lists what the role allows, in the table's order: `read`, `participate`, `triage`, `push`, `merge`, `run`, `manage_settings`, `manage_protection`, `manage_integrations`, `manage_access`, `administer` and `delete` (which also takes an owner of the workspace). `role` and `source` are null, and `capabilities` empty, for someone with no role. Refused with `403` below the Write role, unless you ask about yourself. See [Access and roles](/guides/access-and-roles/)."
4244− },
4245− "list_repo_invitations": {
4246− "response": [
4247− {
4248− "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p",
4249− "repo": "flagon-io/hello",
4250− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4251− "invitee": "alan",
4252− "email": null,
4253− "role": "write",
4254− "invited_by": "syntaqx",
4255− "inviter_avatar": null,
4256− "status": "pending",
4257− "created_at": "2026-10-05T17:00:00.000Z",
4258− "expires_at": "2026-10-12T17:00:00.000Z"
4259− },
4260− {
4261− "id": "rin_01kp3d7e8f9g0h1j2k3m4n5p6q",
4262− "repo": "flagon-io/hello",
4263− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4264− "invitee": null,
4265− "email": "joan@example.com",
4266− "role": "read",
4267− "invited_by": "syntaqx",
4268− "inviter_avatar": null,
4269− "status": "pending",
4270− "created_at": "2026-10-05T17:00:00.000Z",
4271− "expires_at": "2026-10-12T17:00:00.000Z"
4272− }
4273− ],
4274− "notes": "Pending invitations only, newest first. `email` is set for an invitation sent to an address that had no account. Refused with `403` without the Admin role. See [Access and roles](/guides/access-and-roles/)."
4275− },
4276− "revoke_repo_invitation": {
4277− "params": {
4278− "owner": "flagon-io",
4279− "name": "hello",
4280− "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p"
4281− },
4282− "response": {
4283− "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p",
4284− "repo": "flagon-io/hello",
4285− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4286− "invitee": "alan",
4287− "email": null,
4288− "role": "write",
4289− "invited_by": "syntaqx",
4290− "inviter_avatar": null,
4291− "status": "revoked",
4292− "created_at": "2026-10-05T17:00:00.000Z",
4293− "expires_at": "2026-10-12T17:00:00.000Z"
4294− },
4295− "notes": "`404` when there is no pending invitation with that id on this repository."
4296− },
4297− "list_my_repo_invitations": {
4298− "response": [
4299− {
4300− "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4301− "repo": "flagon-io/hello",
4302− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4303− "invitee": "ada",
4304− "email": null,
4305− "role": "triage",
4306− "invited_by": "syntaqx",
4307− "inviter_avatar": null,
4308− "status": "pending",
4309− "created_at": "2026-10-05T17:00:00.000Z",
4310− "expires_at": "2026-10-12T17:00:00.000Z"
4311− }
4312− ],
4313− "notes": "Invitations sent to your username, and to any of your confirmed addresses before you had an account, newest first. Accept one with `PATCH /user/repository_invitations/{id}`, or decline it with `DELETE`. Expired and answered ones are left out."
4314− },
4315− "accept_repo_invitation": {
4316− "params": {
4317− "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r"
4318− },
4319− "response": {
4320− "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4321− "repo": "flagon-io/hello",
4322− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4323− "invitee": "ada",
4324− "email": null,
4325− "role": "triage",
4326− "invited_by": "syntaqx",
4327− "inviter_avatar": null,
4328− "status": "accepted",
4329− "created_at": "2026-10-05T17:00:00.000Z",
4330− "expires_at": "2026-10-12T17:00:00.000Z"
4331− },
4332− "notes": "The role is yours at once. `404` when you have no pending invitation with that id (it may have expired or been revoked), and `403` when your account does not meet what the workspace asks of everyone with access, such as two-factor authentication, with a message that says what to turn on. See [Access and roles](/guides/access-and-roles/)."
4333− },
4334− "decline_repo_invitation": {
4335− "params": {
4336− "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r"
4337− },
4338− "response": {
4339− "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4340− "repo": "flagon-io/hello",
4341− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4342− "invitee": "ada",
4343− "email": null,
4344− "role": "triage",
4345− "invited_by": "syntaqx",
4346− "inviter_avatar": null,
4347− "status": "declined",
4348− "created_at": "2026-10-05T17:00:00.000Z",
4349− "expires_at": "2026-10-12T17:00:00.000Z"
4350− },
4351− "notes": "`404` when you have no pending invitation with that id."
4352− },
4353− "set_base_permission": {
4354− "params": {
4355− "workspace": "flagon-io"
4356− },
4357− "request": {
4358− "base_permission": "read"
4359− },
4360− "response": {
4361− "workspace": "flagon-io",
4362− "base_permission": "read"
4363− },
4364− "notes": "`base_permission` is `none`, `read`, `write` (the default) or `admin`. Owners keep Admin, and a role given on a repository directly still counts where it is higher. Refused with `403` for anyone but an owner signed in as a person. See [Access and roles](/guides/access-and-roles/)."
4365− },
4366− "list_outside_collaborators": {
4367− "params": {
4368− "workspace": "flagon-io"
4369− },
4370− "response": [
4371− {
4372− "username": "ada",
4373− "name": "Ada Lovelace",
4374− "avatar": null,
4375− "repos": [
4376− {
4377− "repo": "flagon-io/docs",
4378− "role": "write"
4379− },
4380− {
4381− "repo": "flagon-io/hello",
4382− "role": "triage"
4383− }
4384− ]
4385− }
4386− ],
4387− "notes": "By username, each with the repositories they have a role on. Refused with `403` for anyone but an owner. See [Access and roles](/guides/access-and-roles/)."
4388− },
4389− "list_teams": {
4390− "params": {
4391− "workspace": "flagon-io"
4392− },
4393− "query": {
4394− "q": "back"
4395− },
4396− "response": [
4397− {
4398− "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4399− "workspace": "flagon-io",
4400− "slug": "backend",
4401− "name": "Backend",
4402− "description": "The API and the services behind it.",
4403− "visibility": "visible",
4404− "parent": {
4405− "slug": "engineering",
4406− "name": "Engineering"
4407− },
4408− "notify": true,
4409− "review_assignment": {
4410− "enabled": false,
4411− "algorithm": "round_robin",
4412− "count": 1,
4413− "skip_busy": false,
4414− "busy_at": 5,
4415− "include_child_teams": false,
4416− "excluded": [],
4417− "notify_team": false
4418− },
4419− "members_count": 4,
4420− "repos_count": 2,
4421− "child_teams_count": 1,
4422− "viewer_role": "maintainer",
4423− "can_manage": true,
4424− "created_at": "2026-10-06T15:02:11.480Z",
4425− "updated_at": "2026-10-06T15:02:11.480Z"
4426− }
4427− ],
4428− "notes": "Teams you are in come first, then the rest by name. A secret team is listed only for its own people and the workspace's owners. `review_assignment` is what happens when the team is asked to review: see [`set_team_review_assignment`](/reference/api/teams/set-team-review-assignment/). `403` for anyone who is not a member of the workspace. See [Teams](/guides/teams/)."
4429− },
4430− "create_team": {
4431− "params": {
4432− "workspace": "flagon-io"
4433− },
4434− "request": {
4435− "name": "Backend",
4436− "description": "The API and the services behind it.",
4437− "visibility": "visible",
4438− "parent": "engineering",
4439− "members": [
4440− "ana"
4441− ]
4442− },
4443− "response": {
4444− "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4445− "workspace": "flagon-io",
4446− "slug": "backend",
4447− "name": "Backend",
4448− "description": "The API and the services behind it.",
4449− "visibility": "visible",
4450− "parent": {
4451− "slug": "engineering",
4452− "name": "Engineering"
4453− },
4454− "notify": true,
4455− "review_assignment": {
4456− "enabled": false,
4457− "algorithm": "round_robin",
4458− "count": 1,
4459− "skip_busy": false,
4460− "busy_at": 5,
4461− "include_child_teams": false,
4462− "excluded": [],
4463− "notify_team": false
4464− },
4465− "members_count": 2,
4466− "repos_count": 0,
4467− "child_teams_count": 0,
4468− "viewer_role": "maintainer",
4469− "can_manage": true,
4470− "created_at": "2026-10-06T15:02:11.480Z",
4471− "updated_at": "2026-10-06T15:02:11.480Z"
4472− },
4473− "notes": "You become the team's maintainer. Refused with `403` for a member when the workspace's `team_creation` is `owners`. `slug` is made from `name` when left out (`Web & Mobile` becomes `web-mobile`), and `409` says one is taken. A workspace has at most 500 teams, nested at most 8 deep; `name` is at most 80 characters and `description` 280. A `secret` team cannot have a parent or child teams. Refused with `403` for an agent's or a workspace's token. See [Teams](/guides/teams/)."
4474− },
4475− "get_team": {
4476− "params": {
4477− "workspace": "flagon-io",
4478− "team": "backend"
4479− },
4480− "response": {
4481− "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4482− "workspace": "flagon-io",
4483− "slug": "backend",
4484− "name": "Backend",
4485− "description": "The API and the services behind it.",
4486− "visibility": "visible",
4487− "parent": {
4488− "slug": "engineering",
4489− "name": "Engineering"
4490− },
4491− "notify": true,
4492− "review_assignment": {
4493− "enabled": false,
4494− "algorithm": "round_robin",
4495− "count": 1,
4496− "skip_busy": false,
4497− "busy_at": 5,
4498− "include_child_teams": false,
4499− "excluded": [],
4500− "notify_team": false
4501− },
4502− "members_count": 4,
4503− "repos_count": 2,
4504− "child_teams_count": 1,
4505− "viewer_role": "maintainer",
4506− "can_manage": true,
4507− "created_at": "2026-10-06T15:02:11.480Z",
4508− "updated_at": "2026-10-06T15:02:11.480Z"
4509− },
4510− "notes": "`404` for a team that does not exist, or a secret one you are not in, unless you are an owner."
4511− },
4512− "update_team": {
4513− "params": {
4514− "workspace": "flagon-io",
4515− "team": "backend"
4516− },
4517− "request": {
4518− "description": "The API, the services behind it, and their on-call.",
4519− "visibility": "secret",
4520− "parent": ""
4521− },
4522− "response": {
4523− "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4524− "workspace": "flagon-io",
4525− "slug": "backend",
4526− "name": "Backend",
4527− "description": "The API, the services behind it, and their on-call.",
4528− "visibility": "secret",
4529− "parent": null,
4530− "notify": true,
4531− "review_assignment": {
4532− "enabled": false,
4533− "algorithm": "round_robin",
4534− "count": 1,
4535− "skip_busy": false,
4536− "busy_at": 5,
4537− "include_child_teams": false,
4538− "excluded": [],
4539− "notify_team": false
4540− },
4541− "members_count": 4,
4542− "repos_count": 2,
4543− "child_teams_count": 1,
4544− "viewer_role": "maintainer",
4545− "can_manage": true,
4546− "created_at": "2026-10-06T15:02:11.480Z",
4547− "updated_at": "2026-10-07T09:41:52.006Z"
4548− },
4549− "notes": "Only the fields given change. `parent` set to `\"\"` takes the team out from under its parent; a team cannot be nested under itself or one of its own child teams. A new `slug` changes how it is mentioned: `@flagon-io/backend` no longer reaches it. `review_assignment` takes the fields [`set_team_review_assignment`](/reference/api/teams/set-team-review-assignment/) does. Owners of the workspace and the team's maintainers (`403` otherwise)."
4550− },
4551− "delete_team": {
4552− "params": {
4553− "workspace": "flagon-io",
4554− "team": "backend"
4555− },
4556− "response": true,
4557− "notes": "Its child teams move up to its parent, or to the top when it has none. The roles it gave on repositories are taken away, and it is no longer asked to review. Owners of the workspace and the team's maintainers (`403` otherwise)."
4558− },
4559− "list_team_members": {
4560− "params": {
4561− "workspace": "flagon-io",
4562− "team": "backend"
4563− },
4564− "query": {
4565− "include_child_teams": "true"
4566− },
4567− "response": [
4568− {
4569− "username": "syntaqx",
4570− "name": "Chase Pierce",
4571− "avatar": null,
4572− "role": "maintainer",
4573− "via": null
4574− },
4575− {
4576− "username": "ana",
4577− "name": "Ana Lima",
4578− "avatar": null,
4579− "role": "member",
4580− "via": null
4581− },
4582− {
4583− "username": "bo",
4584− "name": null,
4585− "avatar": null,
4586− "role": "member",
4587− "via": "payments"
4588− }
4589− ],
4590− "notes": "Maintainers come first, then members, each by username. With `include_child_teams`, the people of its child teams (and theirs) follow, each with `via`, the child team they are in; someone in both is listed once, as the team's own."
4591− },
4592− "set_team_member": {
4593− "params": {
4594− "workspace": "flagon-io",
4595− "team": "backend",
4596− "username": "ana"
4597− },
4598− "request": {
4599− "role": "maintainer"
4600− },
4601− "response": {
4602− "username": "ana",
4603− "name": "Ana Lima",
4604− "avatar": null,
4605− "role": "maintainer",
4606− "via": null
4607− },
4608− "notes": "`role` is `member` (the default) or `maintainer`. `422` when they are not a member of the workspace: add them to it first. Owners of the workspace and the team's maintainers (`403` otherwise)."
4609− },
4610− "remove_team_member": {
4611− "params": {
4612− "workspace": "flagon-io",
4613− "team": "backend",
4614− "username": "ana"
4615− },
4616− "response": true,
4617− "notes": "Anyone may take themselves out of a team. Leaving the workspace takes a person out of all its teams."
4618− },
4619− "list_child_teams": {
4620− "params": {
4621− "workspace": "flagon-io",
4622− "team": "engineering"
4623− },
4624− "response": [
4625− {
4626− "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4627− "workspace": "flagon-io",
4628− "slug": "backend",
4629− "name": "Backend",
4630− "description": "The API and the services behind it.",
4631− "visibility": "visible",
4632− "parent": {
4633− "slug": "engineering",
4634− "name": "Engineering"
4635− },
4636− "notify": true,
4637− "review_assignment": {
4638− "enabled": false,
4639− "algorithm": "round_robin",
4640− "count": 1,
4641− "skip_busy": false,
4642− "busy_at": 5,
4643− "include_child_teams": false,
4644− "excluded": [],
4645− "notify_team": false
4646− },
4647− "members_count": 4,
4648− "repos_count": 2,
4649− "child_teams_count": 0,
4650− "viewer_role": "maintainer",
4651− "can_manage": true,
4652− "created_at": "2026-10-06T15:02:11.480Z",
4653− "updated_at": "2026-10-06T15:02:11.480Z"
4654− }
4655− ],
4656− "notes": "Only the teams directly under it; read each one's own with this again. A child team inherits its parent's roles on repositories, and a mention or review request for the parent reaches its people too."
4657− },
4658− "list_team_repos": {
4659− "params": {
4660− "workspace": "flagon-io",
4661− "team": "backend"
4662− },
4663− "response": [
4664− {
4665− "repo": "flagon-io/hello",
4666− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4667− "role": "write",
4668− "inherited_from": null
4669− },
4670− {
4671− "repo": "flagon-io/docs",
4672− "repo_id": "rep_01m3m5r2a8c4e6g8j0m2p4r6t8",
4673− "role": "read",
4674− "inherited_from": "engineering"
4675− }
4676− ],
4677− "notes": "A role inherited from a parent team names it in `inherited_from`. Where the team has a role of its own on the same repository, the higher one is listed. Only repositories you can see are listed."
4678− },
4679− "set_team_repo": {
4680− "params": {
4681− "workspace": "flagon-io",
4682− "team": "backend",
4683− "repo": "hello"
4684− },
4685− "request": {
4686− "role": "maintain"
4687− },
4688− "response": {
4689− "repo": "flagon-io/hello",
4690− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4691− "role": "maintain",
4692− "inherited_from": null
4693− },
4694− "notes": "`repo` in the path is the repository's name in the team's workspace; a team has roles only on its own workspace's repositories. `role` is `read`, `triage`, `write`, `maintain` or `admin`. Everyone in the team and its child teams gets it; someone with a higher role otherwise keeps that. Needs the Admin role on the repository (`403` otherwise), and the `access:admin` scope. See [Access and roles](/guides/access-and-roles/)."
4695− },
4696− "remove_team_repo": {
4697− "params": {
4698− "workspace": "flagon-io",
4699− "team": "backend",
4700− "repo": "hello"
4701− },
4702− "response": true,
4703− "notes": "A role the team inherits from a parent is taken away on the parent. Needs the Admin role on the repository, or to be an owner or one of the team's maintainers."
4704− },
4705− "set_team_review_assignment": {
4706− "params": {
4707− "workspace": "flagon-io",
4708− "team": "backend"
4709− },
4710− "request": {
4711− "enabled": true,
4712− "algorithm": "load_balance",
4713− "count": 2,
4714− "skip_busy": true,
4715− "busy_at": 5,
4716− "excluded": [
4717− "syntaqx"
4718− ]
4719− },
4720− "response": {
4721− "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4722− "workspace": "flagon-io",
4723− "slug": "backend",
4724− "name": "Backend",
4725− "description": "The API and the services behind it.",
4726− "visibility": "visible",
4727− "parent": {
4728− "slug": "engineering",
4729− "name": "Engineering"
4730− },
4731− "notify": true,
4732− "review_assignment": {
4733− "enabled": true,
4734− "algorithm": "load_balance",
4735− "count": 2,
4736− "skip_busy": true,
4737− "busy_at": 5,
4738− "include_child_teams": false,
4739− "excluded": [
4740− "syntaqx"
4741− ],
4742− "notify_team": false
4743− },
4744− "members_count": 4,
4745− "repos_count": 2,
4746− "child_teams_count": 1,
4747− "viewer_role": "maintainer",
4748− "can_manage": true,
4749− "created_at": "2026-10-06T15:02:11.480Z",
4750− "updated_at": "2026-10-07T09:44:03.512Z"
4751− },
4752− "notes": "| Field | |\n| --- | --- |\n| `enabled` | Off, everyone in the team is asked. On, `count` people are picked and asked, and the team stays shown as asked beside them. |\n| `algorithm` | `round_robin`: whoever this team asked least recently. `load_balance`: whoever has the fewest pull requests waiting on their review. |\n| `count` | How many to pick, 1 to 10. People from the team already asked count towards it. |\n| `skip_busy`, `busy_at` | Leave out anyone with `busy_at` (1 to 100) or more pull requests waiting on their review. |\n| `include_child_teams` | Also pick from its child teams' people. |\n| `excluded` | Usernames never picked. Replaces the whole list. |\n| `notify_team` | Also tell the rest of the team when people are picked. |\n\nFields left out keep their value. The pull request's author is never picked. See [Teams](/guides/teams/)."
4753− },
4754− "list_user_teams": {
4755− "params": {
4756− "workspace": "flagon-io",
4757− "username": "ana"
4758− },
4759− "response": [
4760− {
4761− "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4762− "workspace": "flagon-io",
4763− "slug": "backend",
4764− "name": "Backend",
4765− "description": "The API and the services behind it.",
4766− "visibility": "visible",
4767− "parent": {
4768− "slug": "engineering",
4769− "name": "Engineering"
4770− },
4771− "notify": true,
4772− "review_assignment": {
4773− "enabled": false,
4774− "algorithm": "round_robin",
4775− "count": 1,
4776− "skip_busy": false,
4777− "busy_at": 5,
4778− "include_child_teams": false,
4779− "excluded": [],
4780− "notify_team": false
4781− },
4782− "members_count": 4,
4783− "repos_count": 2,
4784− "child_teams_count": 1,
4785− "viewer_role": null,
4786− "can_manage": false,
4787− "created_at": "2026-10-06T15:02:11.480Z",
4788− "updated_at": "2026-10-06T15:02:11.480Z"
4789− }
4790− ],
4791− "notes": "Only the teams they are in themselves, not the parents those teams are under. Secret teams you are not in are left out unless you are an owner. `403` for anyone who is not a member of the workspace."
4792− },
4793− "list_security_alerts": {
4794− "params": {
4795− "owner": "flagon-io",
4796− "name": "hello"
4797− },
4798− "query": {
4799− "state": "open"
4800− },
4801− "response": [
4802− {
4803− "kind": "secret",
4804− "id": "sec_01kp4a7b2c3d4e5f6g7h8j9k0m",
4805− "state": "dismissed",
4806− "secret_type": "aws_access_key",
4807− "label": "an AWS access key",
4808− "path": "test/fixtures/aws.env",
4809− "line": 3,
4810− "commit": "9f2c1e04b7d3a8e6f5c2b1a0d9e8f7c6b5a4d3e2",
4811− "preview": "AKIA…MPLE",
4812− "status": "allowed",
4813− "source": "history",
4814− "test_value": "the documented example key",
4815− "found_by": null,
4816− "found_at": "2026-10-01T12:00:00.000Z",
4817− "dismissed_reason": "used_in_tests",
4818− "dismissed_comment": "Only in the test fixtures.",
4819− "dismissed_by": "syntaqx",
4820− "dismissed_at": "2026-10-02T09:15:00.000Z"
4821− },
4822− {
4823− "kind": "dependency",
4824− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
4825− "state": "open",
4826− "ecosystem": "npm",
4827− "package": "lodash",
4828− "version": "4.17.20",
4829− "manifest": "package-lock.json",
4830− "advisory": "GHSA-35jh-r3h4-6jhm",
4831− "osv_id": "GHSA-35jh-r3h4-6jhm",
4832− "summary": "Command Injection in lodash",
4833− "severity": "high",
4834− "fixed_version": "4.17.21",
4835− "fixed_at": null,
4836− "update": {
4837− "state": "open",
4838− "target": "4.17.21",
4839− "branch": "g1t/security/lodash-4.17.21",
4840− "pull": 42,
4841− "issue": null,
4842− "error": null,
4843− "updated_at": "2026-10-01T12:20:00.000Z"
4844− },
4845− "found_at": "2026-10-01T12:00:00.000Z",
4846− "dismissed_reason": null,
4847− "dismissed_comment": null,
4848− "dismissed_by": null,
4849− "dismissed_at": null
4850− }
4851− ],
4852− "notes": "Secrets come first, then dependencies. Fields only one kind has are left out of the other: a secret has `secret_type`, `label`, `path`, `line`, `commit`, `preview`, `status` (`open`, `blocked`, `allowed` or `resolved`), `source` (`push` or `history`), `test_value` and `found_by`; a dependency has `ecosystem`, `package`, `version`, `manifest`, `advisory`, `osv_id`, `summary`, `severity`, `fixed_version` (null when no patched version is available), `fixed_at` and `update`, the pull request g1t opens to upgrade it. `dismissed_reason`, `dismissed_comment`, `dismissed_by` and `dismissed_at` are null while an alert is open; a secret fixed by being revoked keeps them. `422` for a `state` or `kind` it does not know, and `404` for anyone without the Write role. See [Security](/guides/security/)."
4853− },
4854− "dismiss_security_alert": {
4855− "params": {
4856− "owner": "flagon-io",
4857− "name": "hello",
4858− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n"
4859− },
4860− "request": {
4861− "reason": "tolerable_risk",
4862− "comment": "Only the build uses it, on trusted input."
4863− },
4864− "response": {
4865− "kind": "dependency",
4866− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
4867− "state": "dismissed",
4868− "ecosystem": "npm",
4869− "package": "lodash",
4870− "version": "4.17.20",
4871− "manifest": "package-lock.json",
4872− "advisory": "GHSA-35jh-r3h4-6jhm",
4873− "osv_id": "GHSA-35jh-r3h4-6jhm",
4874− "summary": "Command Injection in lodash",
4875− "severity": "high",
4876− "fixed_version": "4.17.21",
4877− "fixed_at": null,
4878− "update": {
4879− "state": "open",
4880− "target": "4.17.21",
4881− "branch": "g1t/security/lodash-4.17.21",
4882− "pull": 42,
4883− "issue": null,
4884− "error": null,
4885− "updated_at": "2026-10-01T12:20:00.000Z"
4886− },
4887− "found_at": "2026-10-01T12:00:00.000Z",
4888− "dismissed_reason": "tolerable_risk",
4889− "dismissed_comment": "Only the build uses it, on trusted input.",
4890− "dismissed_by": "syntaqx",
4891− "dismissed_at": "2026-10-06T10:00:00.000Z"
4892− },
4893− "notes": "| Kind | Reasons |\n| --- | --- |\n| `secret` | `false_positive`, `used_in_tests`, `revoked`, `wont_fix` |\n| `dependency` | `fix_started`, `no_bandwidth`, `tolerable_risk`, `inaccurate`, `not_used` |\n\nA reason for the other kind of alert, or one not in the table, is refused with `422`. A secret dismissed as `revoked` becomes `fixed`; with any other reason it becomes `dismissed` and pushes that carry it go through. Dismissing a secret needs the Admin role on the repository; a dependency needs the Write role. A token needs `repo:admin` for either, and a g1t agent’s token never dismisses alerts."
4894− },
4895− "reopen_security_alert": {
4896− "params": {
4897− "owner": "flagon-io",
4898− "name": "hello",
4899− "id": "sec_01kp4a7b2c3d4e5f6g7h8j9k0m"
4900− },
4901− "response": {
4902− "kind": "secret",
4903− "id": "sec_01kp4a7b2c3d4e5f6g7h8j9k0m",
4904− "state": "open",
4905− "secret_type": "aws_access_key",
4906− "label": "an AWS access key",
4907− "path": "test/fixtures/aws.env",
4908− "line": 3,
4909− "commit": "9f2c1e04b7d3a8e6f5c2b1a0d9e8f7c6b5a4d3e2",
4910− "preview": "AKIA…MPLE",
4911− "status": "open",
4912− "source": "history",
4913− "test_value": "the documented example key",
4914− "found_by": null,
4915− "found_at": "2026-10-01T12:00:00.000Z",
4916− "dismissed_reason": null,
4917− "dismissed_comment": null,
4918− "dismissed_by": null,
4919− "dismissed_at": null
4920− },
4921− "notes": "The alert is `open` again, and a reopened secret stops pushes that carry it. The same roles as dismissing: Admin for a secret, Write for a dependency."
4922− },
4923− "list_notifications": {
4924− "query": {
4925− "participating": "true"
4926− },
4927− "response": {
4928− "items": [
4929− {
4930− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
4931− "reason": "review_requested",
4932− "severity": "warning",
4933− "title": "ada asked you to review flagon-io/hello#14",
4934− "body": "Add a greeting to the README",
4935− "event": "pull.review_requested",
4936− "repo": "flagon-io/hello",
4937− "workspace": "flagon-io",
4938− "subject": "pull",
4939− "number": 14,
4940− "url": "/flagon-io/hello/pull/14",
4941− "actor": "ada",
4942− "count": 3,
4943− "created_at": "2026-10-06T15:02:11.000Z",
4944− "updated_at": "2026-10-07T09:41:30.000Z",
4945− "read_at": null,
4946− "done_at": null,
4947− "saved": false,
4948− "snoozed_until": null
4949− },
4950− {
4951− "id": "ntf_01kp7k9a8b7c6d5e4f3g2h1j0k",
4952− "reason": "ci_activity",
4953− "severity": "error",
4954− "title": "Production of hello failed to deploy",
4955− "body": "The build failed: npm run build exited with 1.",
4956− "event": "deployment.failed",
4957− "repo": "flagon-io/hello",
4958− "workspace": "flagon-io",
4959− "subject": "deploy",
4960− "number": null,
4961− "url": "/flagon-io/hello/deployments/dpl_01kp7k8z7y6x5w4v3t2s1r0q9p",
4962− "actor": "syntaqx",
4963− "count": 1,
4964− "created_at": "2026-10-07T08:12:40.000Z",
4965− "updated_at": "2026-10-07T08:12:40.000Z",
4966− "read_at": null,
4967− "done_at": null,
4968− "saved": false,
4969− "snoozed_until": null
4970− }
4971− ],
4972− "next": null
4973− },
4974− "notes": "Unread threads only, unless `all=true`. Threads that wait on you (an agent, or a review asked of you) have severity `warning`.\n\n| `reason` | You were told because |\n| --- | --- |\n| `agent` | An agent is waiting on you: it asked a question, or g1t stopped until a person steps in |\n| `review_requested` | You were asked to review |\n| `assign` | You were assigned |\n| `mention` | Someone mentioned you by `@username` |\n| `ci_activity` | Checks, a workflow or a deployment on your work finished |\n| `security_alert` | A security alert on a repository you look after |\n| `state_change` | It was closed, reopened or merged |\n| `author` | You opened it, or asked g1t for it |\n| `comment` | You commented on it |\n| `manual` | You subscribed to it by hand |\n| `subscribed` | You watch its repository |\n\nWith `participating=true`, threads you only follow (`manual`, `subscribed`) are left out. For the next page, pass `next` as `cursor`; `next` is null on the last."
4975− },
4976− "list_repo_notifications": {
4977− "params": {
4978− "owner": "flagon-io",
4979− "name": "hello"
4980− },
4981− "query": {
4982− "all": "true"
4983− },
4984− "response": {
4985− "items": [
4986− {
4987− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
4988− "reason": "review_requested",
4989− "severity": "warning",
4990− "title": "ada asked you to review flagon-io/hello#14",
4991− "body": "Add a greeting to the README",
4992− "event": "pull.review_requested",
4993− "repo": "flagon-io/hello",
4994− "workspace": "flagon-io",
4995− "subject": "pull",
4996− "number": 14,
4997− "url": "/flagon-io/hello/pull/14",
4998− "actor": "ada",
4999− "count": 3,
5000− "created_at": "2026-10-06T15:02:11.000Z",
5001− "updated_at": "2026-10-07T09:41:30.000Z",
5002− "read_at": "2026-10-07T09:50:00.000Z",
5003− "done_at": null,
5004− "saved": false,
5005− "snoozed_until": null
5006− },
5007− {
5008− "id": "ntf_01kp7k9a8b7c6d5e4f3g2h1j0k",
5009− "reason": "ci_activity",
5010− "severity": "error",
5011− "title": "Production of hello failed to deploy",
5012− "body": "The build failed: npm run build exited with 1.",
5013− "event": "deployment.failed",
5014− "repo": "flagon-io/hello",
5015− "workspace": "flagon-io",
5016− "subject": "deploy",
5017− "number": null,
5018− "url": "/flagon-io/hello/deployments/dpl_01kp7k8z7y6x5w4v3t2s1r0q9p",
5019− "actor": "syntaqx",
5020− "count": 1,
5021− "created_at": "2026-10-07T08:12:40.000Z",
5022− "updated_at": "2026-10-07T08:12:40.000Z",
5023− "read_at": null,
5024− "done_at": null,
5025− "saved": false,
5026− "snoozed_until": null
5027− }
5028− ],
5029− "next": "ntf_01kp7k9a8b7c6d5e4f3g2h1j0k"
5030− },
5031− "notes": "The same as `GET /notifications`, for one repository you can read."
5032− },
5033− "mark_notifications_read": {
5034− "request": {
5035− "last_read_at": "2026-10-07T10:00:00Z"
5036− },
5037− "response": {
5038− "marked": 12,
5039− "last_read_at": "2026-10-07T10:00:00.000Z"
5040− },
5041− "notes": "Threads with activity after `last_read_at` stay unread, so send the time you last listed them."
5042− },
5043− "mark_repo_notifications_read": {
5044− "params": {
5045− "owner": "flagon-io",
5046− "name": "hello"
5047− },
5048− "request": {},
5049− "response": {
5050− "marked": 3,
5051− "last_read_at": "2026-10-07T10:02:41.512Z"
5052− }
5053− },
5054− "get_notification_thread": {
5055− "params": {
5056− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5057− },
5058− "response": {
5059− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5060− "reason": "review_requested",
5061− "severity": "warning",
5062− "title": "ada asked you to review flagon-io/hello#14",
5063− "body": "Add a greeting to the README",
5064− "event": "pull.review_requested",
5065− "repo": "flagon-io/hello",
5066− "workspace": "flagon-io",
5067− "subject": "pull",
5068− "number": 14,
5069− "url": "/flagon-io/hello/pull/14",
5070− "actor": "ada",
5071− "count": 3,
5072− "created_at": "2026-10-06T15:02:11.000Z",
5073− "updated_at": "2026-10-07T09:41:30.000Z",
5074− "read_at": null,
5075− "done_at": null,
5076− "saved": false,
5077− "snoozed_until": null,
5078− "activity": [
5079− {
5080− "reason": "review_requested",
5081− "severity": "warning",
5082− "title": "ada asked you to review flagon-io/hello#14",
5083− "body": "Add a greeting to the README",
5084− "event": "pull.review_requested",
5085− "actor": "ada",
5086− "created_at": "2026-10-07T09:41:30.000Z"
5087− },
5088− {
5089− "reason": "comment",
5090− "severity": "info",
5091− "title": "ada commented on flagon-io/hello#14",
5092− "body": "Pushed the fix for the heading.",
5093− "event": "comment.created",
5094− "actor": "ada",
5095− "created_at": "2026-10-06T18:20:02.000Z"
5096− },
5097− {
5098− "reason": "comment",
5099− "severity": "info",
5100− "title": "g1t commented on flagon-io/hello#14",
5101− "body": "The heading level is off by one.",
5102− "event": "comment.created",
5103− "actor": "g1t",
5104− "created_at": "2026-10-06T15:02:11.000Z"
5105− }
5106− ],
5107− "subscription": {
5108− "subscribed": true,
5109− "ignored": false,
5110− "reason": "review_requested",
5111− "repo": "flagon-io/hello",
5112− "number": 14,
5113− "updated_at": null
5114− }
5115− },
5116− "notes": "`activity` keeps the last 10 things that happened on the thread, newest first; `count` is how many there have been. `subscription` is null for a workflow or a deployment, which nobody subscribes to."
5117− },
5118− "mark_thread_read": {
5119− "params": {
5120− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5121− },
5122− "request": {},
5123− "response": {
5124− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5125− "reason": "review_requested",
5126− "severity": "warning",
5127− "title": "ada asked you to review flagon-io/hello#14",
5128− "body": "Add a greeting to the README",
5129− "event": "pull.review_requested",
5130− "repo": "flagon-io/hello",
5131− "workspace": "flagon-io",
5132− "subject": "pull",
5133− "number": 14,
5134− "url": "/flagon-io/hello/pull/14",
5135− "actor": "ada",
5136− "count": 3,
5137− "created_at": "2026-10-06T15:02:11.000Z",
5138− "updated_at": "2026-10-07T09:41:30.000Z",
5139− "read_at": "2026-10-07T10:03:00.000Z",
5140− "done_at": null,
5141− "saved": false,
5142− "snoozed_until": null,
5143− "activity": [
5144− {
5145− "reason": "review_requested",
5146− "severity": "warning",
5147− "title": "ada asked you to review flagon-io/hello#14",
5148− "body": "Add a greeting to the README",
5149− "event": "pull.review_requested",
5150− "actor": "ada",
5151− "created_at": "2026-10-07T09:41:30.000Z"
5152− },
5153− {
5154− "reason": "comment",
5155− "severity": "info",
5156− "title": "ada commented on flagon-io/hello#14",
5157− "body": "Pushed the fix for the heading.",
5158− "event": "comment.created",
5159− "actor": "ada",
5160− "created_at": "2026-10-06T18:20:02.000Z"
5161− },
5162− {
5163− "reason": "comment",
5164− "severity": "info",
5165− "title": "g1t commented on flagon-io/hello#14",
5166− "body": "The heading level is off by one.",
5167− "event": "comment.created",
5168− "actor": "g1t",
5169− "created_at": "2026-10-06T15:02:11.000Z"
5170− }
5171− ],
5172− "subscription": {
5173− "subscribed": true,
5174− "ignored": false,
5175− "reason": "review_requested",
5176− "repo": "flagon-io/hello",
5177− "number": 14,
5178− "updated_at": null
5179− }
5180− }
5181− },
5182− "mark_thread_done": {
5183− "params": {
5184− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5185− },
5186− "response": {
5187− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5188− "reason": "review_requested",
5189− "severity": "warning",
5190− "title": "ada asked you to review flagon-io/hello#14",
5191− "body": "Add a greeting to the README",
5192− "event": "pull.review_requested",
5193− "repo": "flagon-io/hello",
5194− "workspace": "flagon-io",
5195− "subject": "pull",
5196− "number": 14,
5197− "url": "/flagon-io/hello/pull/14",
5198− "actor": "ada",
5199− "count": 3,
5200− "created_at": "2026-10-06T15:02:11.000Z",
5201− "updated_at": "2026-10-07T09:41:30.000Z",
5202− "read_at": "2026-10-07T10:03:00.000Z",
5203− "done_at": "2026-10-07T10:03:00.000Z",
5204− "saved": false,
5205− "snoozed_until": null,
5206− "activity": [
5207− {
5208− "reason": "review_requested",
5209− "severity": "warning",
5210− "title": "ada asked you to review flagon-io/hello#14",
5211− "body": "Add a greeting to the README",
5212− "event": "pull.review_requested",
5213− "actor": "ada",
5214− "created_at": "2026-10-07T09:41:30.000Z"
5215− },
5216− {
5217− "reason": "comment",
5218− "severity": "info",
5219− "title": "ada commented on flagon-io/hello#14",
5220− "body": "Pushed the fix for the heading.",
5221− "event": "comment.created",
5222− "actor": "ada",
5223− "created_at": "2026-10-06T18:20:02.000Z"
5224− },
5225− {
5226− "reason": "comment",
5227− "severity": "info",
5228− "title": "g1t commented on flagon-io/hello#14",
5229− "body": "The heading level is off by one.",
5230− "event": "comment.created",
5231− "actor": "g1t",
5232− "created_at": "2026-10-06T15:02:11.000Z"
5233− }
5234− ],
5235− "subscription": {
5236− "subscribed": true,
5237− "ignored": false,
5238− "reason": "review_requested",
5239− "repo": "flagon-io/hello",
5240− "number": 14,
5241− "updated_at": null
5242− }
5243− },
5244− "notes": "New activity on a done thread brings it back to the inbox, unread."
5245− },
5246− "save_thread": {
5247− "params": {
5248− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5249− },
5250− "request": {},
5251− "response": {
5252− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5253− "reason": "review_requested",
5254− "severity": "warning",
5255− "title": "ada asked you to review flagon-io/hello#14",
5256− "body": "Add a greeting to the README",
5257− "event": "pull.review_requested",
5258− "repo": "flagon-io/hello",
5259− "workspace": "flagon-io",
5260− "subject": "pull",
5261− "number": 14,
5262− "url": "/flagon-io/hello/pull/14",
5263− "actor": "ada",
5264− "count": 3,
5265− "created_at": "2026-10-06T15:02:11.000Z",
5266− "updated_at": "2026-10-07T09:41:30.000Z",
5267− "read_at": null,
5268− "done_at": null,
5269− "saved": true,
5270− "snoozed_until": null,
5271− "activity": [
5272− {
5273− "reason": "review_requested",
5274− "severity": "warning",
5275− "title": "ada asked you to review flagon-io/hello#14",
5276− "body": "Add a greeting to the README",
5277− "event": "pull.review_requested",
5278− "actor": "ada",
5279− "created_at": "2026-10-07T09:41:30.000Z"
5280− },
5281− {
5282− "reason": "comment",
5283− "severity": "info",
5284− "title": "ada commented on flagon-io/hello#14",
5285− "body": "Pushed the fix for the heading.",
5286− "event": "comment.created",
5287− "actor": "ada",
5288− "created_at": "2026-10-06T18:20:02.000Z"
5289− },
5290− {
5291− "reason": "comment",
5292− "severity": "info",
5293− "title": "g1t commented on flagon-io/hello#14",
5294− "body": "The heading level is off by one.",
5295− "event": "comment.created",
5296− "actor": "g1t",
5297− "created_at": "2026-10-06T15:02:11.000Z"
5298− }
5299− ],
5300− "subscription": {
5301− "subscribed": true,
5302− "ignored": false,
5303− "reason": "review_requested",
5304− "repo": "flagon-io/hello",
5305− "number": 14,
5306− "updated_at": null
5307− }
5308− }
5309− },
5310− "unsave_thread": {
5311− "params": {
5312− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5313− },
5314− "response": {
5315− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5316− "reason": "review_requested",
5317− "severity": "warning",
5318− "title": "ada asked you to review flagon-io/hello#14",
5319− "body": "Add a greeting to the README",
5320− "event": "pull.review_requested",
5321− "repo": "flagon-io/hello",
5322− "workspace": "flagon-io",
5323− "subject": "pull",
5324− "number": 14,
5325− "url": "/flagon-io/hello/pull/14",
5326− "actor": "ada",
5327− "count": 3,
5328− "created_at": "2026-10-06T15:02:11.000Z",
5329− "updated_at": "2026-10-07T09:41:30.000Z",
5330− "read_at": null,
5331− "done_at": null,
5332− "saved": false,
5333− "snoozed_until": null,
5334− "activity": [
5335− {
5336− "reason": "review_requested",
5337− "severity": "warning",
5338− "title": "ada asked you to review flagon-io/hello#14",
5339− "body": "Add a greeting to the README",
5340− "event": "pull.review_requested",
5341− "actor": "ada",
5342− "created_at": "2026-10-07T09:41:30.000Z"
5343− },
5344− {
5345− "reason": "comment",
5346− "severity": "info",
5347− "title": "ada commented on flagon-io/hello#14",
5348− "body": "Pushed the fix for the heading.",
5349− "event": "comment.created",
5350− "actor": "ada",
5351− "created_at": "2026-10-06T18:20:02.000Z"
5352− },
5353− {
5354− "reason": "comment",
5355− "severity": "info",
5356− "title": "g1t commented on flagon-io/hello#14",
5357− "body": "The heading level is off by one.",
5358− "event": "comment.created",
5359− "actor": "g1t",
5360− "created_at": "2026-10-06T15:02:11.000Z"
5361− }
5362− ],
5363− "subscription": {
5364− "subscribed": true,
5365− "ignored": false,
5366− "reason": "review_requested",
5367− "repo": "flagon-io/hello",
5368− "number": 14,
5369− "updated_at": null
5370− }
5371− }
5372− },
5373− "snooze_thread": {
5374− "params": {
5375− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5376− },
5377− "request": {
5378− "until": "2026-10-08T09:00:00Z"
5379− },
5380− "response": {
5381− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5382− "reason": "review_requested",
5383− "severity": "warning",
5384− "title": "ada asked you to review flagon-io/hello#14",
5385− "body": "Add a greeting to the README",
5386− "event": "pull.review_requested",
5387− "repo": "flagon-io/hello",
5388− "workspace": "flagon-io",
5389− "subject": "pull",
5390− "number": 14,
5391− "url": "/flagon-io/hello/pull/14",
5392− "actor": "ada",
5393− "count": 3,
5394− "created_at": "2026-10-06T15:02:11.000Z",
5395− "updated_at": "2026-10-07T09:41:30.000Z",
5396− "read_at": "2026-10-07T10:03:00.000Z",
5397− "done_at": null,
5398− "saved": false,
5399− "snoozed_until": "2026-10-08T09:00:00.000Z",
5400− "activity": [
5401− {
5402− "reason": "review_requested",
5403− "severity": "warning",
5404− "title": "ada asked you to review flagon-io/hello#14",
5405− "body": "Add a greeting to the README",
5406− "event": "pull.review_requested",
5407− "actor": "ada",
5408− "created_at": "2026-10-07T09:41:30.000Z"
5409− },
5410− {
5411− "reason": "comment",
5412− "severity": "info",
5413− "title": "ada commented on flagon-io/hello#14",
5414− "body": "Pushed the fix for the heading.",
5415− "event": "comment.created",
5416− "actor": "ada",
5417− "created_at": "2026-10-06T18:20:02.000Z"
5418− },
5419− {
5420− "reason": "comment",
5421− "severity": "info",
5422− "title": "g1t commented on flagon-io/hello#14",
5423− "body": "The heading level is off by one.",
5424− "event": "comment.created",
5425− "actor": "g1t",
5426− "created_at": "2026-10-06T15:02:11.000Z"
5427− }
5428− ],
5429− "subscription": {
5430− "subscribed": true,
5431− "ignored": false,
5432− "reason": "review_requested",
5433− "repo": "flagon-io/hello",
5434− "number": 14,
5435− "updated_at": null
5436− }
5437− }
5438− },
5439− "unsnooze_thread": {
5440− "params": {
5441− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5442− },
5443− "response": {
5444− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5445− "reason": "review_requested",
5446− "severity": "warning",
5447− "title": "ada asked you to review flagon-io/hello#14",
5448− "body": "Add a greeting to the README",
5449− "event": "pull.review_requested",
5450− "repo": "flagon-io/hello",
5451− "workspace": "flagon-io",
5452− "subject": "pull",
5453− "number": 14,
5454− "url": "/flagon-io/hello/pull/14",
5455− "actor": "ada",
5456− "count": 3,
5457− "created_at": "2026-10-06T15:02:11.000Z",
5458− "updated_at": "2026-10-07T09:41:30.000Z",
5459− "read_at": "2026-10-07T10:03:00.000Z",
5460− "done_at": null,
5461− "saved": false,
5462− "snoozed_until": null,
5463− "activity": [
5464− {
5465− "reason": "review_requested",
5466− "severity": "warning",
5467− "title": "ada asked you to review flagon-io/hello#14",
5468− "body": "Add a greeting to the README",
5469− "event": "pull.review_requested",
5470− "actor": "ada",
5471− "created_at": "2026-10-07T09:41:30.000Z"
5472− },
5473− {
5474− "reason": "comment",
5475− "severity": "info",
5476− "title": "ada commented on flagon-io/hello#14",
5477− "body": "Pushed the fix for the heading.",
5478− "event": "comment.created",
5479− "actor": "ada",
5480− "created_at": "2026-10-06T18:20:02.000Z"
5481− },
5482− {
5483− "reason": "comment",
5484− "severity": "info",
5485− "title": "g1t commented on flagon-io/hello#14",
5486− "body": "The heading level is off by one.",
5487− "event": "comment.created",
5488− "actor": "g1t",
5489− "created_at": "2026-10-06T15:02:11.000Z"
5490− }
5491− ],
5492− "subscription": {
5493− "subscribed": true,
5494− "ignored": false,
5495− "reason": "review_requested",
5496− "repo": "flagon-io/hello",
5497− "number": 14,
5498− "updated_at": null
5499− }
5500− }
5501− },
5502− "get_thread_subscription": {
5503− "params": {
5504− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5505− },
5506− "response": {
5507− "subscribed": true,
5508− "ignored": false,
5509− "reason": "review_requested",
5510− "repo": "flagon-io/hello",
5511− "number": 14,
5512− "updated_at": null
5513− }
5514− },
5515− "set_thread_subscription": {
5516− "params": {
5517− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5518− },
5519− "request": {
5520− "ignored": true
5521− },
5522− "response": {
5523− "subscribed": false,
5524− "ignored": true,
5525− "reason": null,
5526− "repo": "flagon-io/hello",
5527− "number": 14,
5528− "updated_at": "2026-10-07T10:04:00.000Z"
5529− },
5530− "notes": "| Body | Then |\n| --- | --- |\n| `{}` or `{\"subscribed\": true}` | You hear of what happens on it |\n| `{\"subscribed\": false}` | You hear only of what is asked of you |\n| `{\"ignored\": true}` | You hear of nothing on it, not even a mention |"
5531− },
5532− "delete_thread_subscription": {
5533− "params": {
5534− "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5535− },
5536− "response": {
5537− "subscribed": false,
5538− "ignored": false,
5539− "reason": null,
5540− "repo": "flagon-io/hello",
5541− "number": 14,
5542− "updated_at": "2026-10-07T10:04:00.000Z"
5543− }
5544− },
5545− "get_issue_subscription": {
5546− "params": {
5547− "owner": "flagon-io",
5548− "name": "hello",
5549− "number": 14
5550− },
5551− "response": {
5552− "subscribed": true,
5553− "ignored": false,
5554− "reason": "author",
5555− "repo": null,
5556− "number": 14,
5557− "updated_at": null
5558− }
5559− },
5560− "set_issue_subscription": {
5561− "params": {
5562− "owner": "flagon-io",
5563− "name": "hello",
5564− "number": 14
5565− },
5566− "request": {
5567− "subscribed": true
5568− },
5569− "response": {
5570− "subscribed": true,
5571− "ignored": false,
5572− "reason": "manual",
5573− "repo": null,
5574− "number": 14,
5575− "updated_at": "2026-10-07T10:05:00.000Z"
5576− }
5577− },
5578− "delete_issue_subscription": {
5579− "params": {
5580− "owner": "flagon-io",
5581− "name": "hello",
5582− "number": 14
5583− },
5584− "response": {
5585− "subscribed": false,
5586− "ignored": false,
5587− "reason": null,
5588− "repo": null,
5589− "number": 14,
5590− "updated_at": "2026-10-07T10:05:30.000Z"
5591− }
5592− },
5593− "get_repo_subscription": {
5594− "params": {
5595− "owner": "flagon-io",
5596− "name": "hello"
5597− },
5598− "response": {
5599− "repo": "flagon-io/hello",
5600− "level": "participating",
5601− "events": [],
5602− "subscribed": false,
5603− "ignored": false,
5604− "updated_at": null
5605− }
5606− },
5607− "set_repo_subscription": {
5608− "params": {
5609− "owner": "flagon-io",
5610− "name": "hello"
5611− },
5612− "request": {
5613− "level": "custom",
5614− "events": [
5615− "pulls",
5616− "deployments"
5617− ]
5618− },
5619− "response": {
5620− "repo": "flagon-io/hello",
5621− "level": "custom",
5622− "events": [
5623− "pulls",
5624− "deployments"
5625− ],
5626− "subscribed": true,
5627− "ignored": false,
5628− "updated_at": "2026-10-07T10:06:00.000Z"
5629− },
5630− "notes": "| `level` | You hear of |\n| --- | --- |\n| `participating` | What you take part in, or are mentioned in (the default) |\n| `all` | Every issue and pull request opened, commented on, closed or merged, and every deployment |\n| `custom` | What you take part in, and the kinds in `events`: `issues`, `pulls`, `deployments`, `security` |\n| `ignore` | Nothing, not even a mention |\n\nInstead of `level`, `{\"subscribed\": true}` is `all`, `{\"subscribed\": false}` is `participating` and `{\"ignored\": true}` is `ignore`."
5631− },
5632− "delete_repo_subscription": {
5633− "params": {
5634− "owner": "flagon-io",
5635− "name": "hello"
5636− },
5637− "response": {
5638− "repo": "flagon-io/hello",
5639− "level": "participating",
5640− "events": [],
5641− "subscribed": false,
5642− "ignored": false,
5643− "updated_at": null
5644− }
5645− },
5646− "list_watched_repos": {
5647− "response": [
5648− {
5649− "repo": "flagon-io/hello",
5650− "level": "all",
5651− "events": [],
5652− "subscribed": true,
5653− "ignored": false,
5654− "updated_at": "2026-10-07T10:00:00.000Z"
5655− },
5656− {
5657− "repo": "flagon-io/docs",
5658− "level": "ignore",
5659− "events": [],
5660− "subscribed": false,
5661− "ignored": true,
5662− "updated_at": "2026-10-05T14:30:00.000Z"
5663− }
5664− ]
5665− },
5666− "get_usage": {
5667− "params": {
5668− "workspace": "flagon-io"
5669− },
5670− "query": {
5671− "from": "2026-10-01",
5672− "until": "2026-10-07",
5673− "group_by": "project"
5674− },
5675− "response": {
5676− "from": "2026-10-01",
5677− "until": "2026-10-07",
5678− "totals": {
5679− "price_micros": 48210000,
5680− "discount_micros": 0,
5681− "included_micros": 20000000,
5682− "credits_micros": 18000000,
5683− "charged_micros": 10210000,
5684− "pending_micros": 1340000,
5685− "cost_micros": 40100000
5686− },
5687− "days": [
5688− {
5689− "day": "2026-10-06",
5690− "product": "agent",
5691− "micros": 12400000
5692− },
5693− {
5694− "day": "2026-10-06",
5695− "product": "sandboxes",
5696− "micros": 2100000
5697− },
5698− {
5699− "day": "2026-10-07",
5700− "product": "agent",
5701− "micros": 9800000
5702− }
5703− ],
5704− "products": [
5705− {
5706− "key": "agent",
5707− "label": "Agent",
5708− "micros": 41000000,
5709− "meters": [
5710− {
5711− "key": "agent_models",
5712− "label": "Models",
5713− "product": "agent",
5714− "unit": "tokens",
5715− "quantity": 9120000,
5716− "micros": 41000000,
5717− "pending_micros": 0,
5718− "daily": [
5719− 3100000,
5720− 5200000,
5721− 4400000,
5722− 6000000,
5723− 0,
5724− 12400000,
5725− 9800000
5726− ],
5727− "allowance": null,
5728− "by_project": [
5729− {
5730− "project": "flagon-io/g1t",
5731− "micros": 36000000,
5732− "quantity": 8010000
5733− },
5734− {
5735− "project": "flagon-io/hello",
5736− "micros": 5000000,
5737− "quantity": 1110000
5738− }
5739− ]
5740− }
5741− ],
5742− "features": [
5743− {
5744− "key": "runs",
5745− "label": "Runs",
5746− "micros": 33000000,
5747− "count": 14
5748− },
5749− {
5750− "key": "reviews",
5751− "label": "Reviews",
5752− "micros": 8000000,
5753− "count": 9
5754− }
5755− ]
5756− },
5757− {
5758− "key": "sandboxes",
5759− "label": "Sandboxes",
5760− "micros": 7210000,
5761− "meters": [
5762− {
5763− "key": "sandbox",
5764− "label": "Sandbox time",
5765− "product": "sandboxes",
5766− "unit": "seconds",
5767− "quantity": 41300,
5768− "micros": 7210000,
5769− "pending_micros": 0,
5770− "daily": [
5771− 900000,
5772− 1200000,
5773− 800000,
5774− 1100000,
5775− 0,
5776− 2100000,
5777− 1110000
5778− ],
5779− "allowance": {
5780− "used": 41300,
5781− "of": 108000,
5782− "unit": "seconds"
5783− },
5784− "by_project": [
5785− {
5786− "project": "flagon-io/g1t",
5787− "micros": 7210000,
5788− "quantity": 41300
5789− }
5790− ]
5791− }
5792− ],
5793− "features": []
5794− }
5795− ],
5796− "projects": [
5797− "flagon-io/g1t",
5798− "flagon-io/hello"
5799− ],
5800− "models": [
5801− {
5802− "model": "claude-sonnet-5-5",
5803− "input": 310000,
5804− "output": 420000,
5805− "cache_read": 7800000,
5806− "cache_write": 590000
5807− }
5808− ],
5809− "included": {
5810− "used": 20,
5811− "of": 20,
5812− "unit": "dollars"
5813− },
5814− "discount_percent": null,
5815− "ai_credit_micros": 62000000,
5816− "credit_micros": 0,
5817− "trial_micros": null,
5818− "plan": "pro",
5819− "free": false,
5820− "group_by": "project",
5821− "groups": [
5822− {
5823− "key": "flagon-io/g1t",
5824− "micros": 43210000
5825− },
5826− {
5827− "key": "flagon-io/hello",
5828− "micros": 5000000
5829− }
5830− ]
5831− },
5832− "notes": "Every product family is listed, in order, even with nothing used; this example shows two. `daily` has one amount for each day of the range, oldest first. `projects` and `products` take several values separated by commas: `?products=agent,sandboxes`. A range of more than 400 days, or one that ends before it starts, is refused with `invalid`."
5833− },
5834− "get_budget": {
5835− "params": {
5836− "workspace": "flagon-io"
5837− },
5838− "response": {
5839− "workspace": "flagon-io",
5840− "amount_micros": 500000000,
5841− "automatic": false,
5842− "spent_micros": 132450000,
5843− "max_amount_micros": 2000000000,
5844− "alerts": [
5845− 50,
5846− 75,
5847− 90,
5848− 100
5849− ],
5850− "pause_at_limit": true,
5851− "webhook": "https://ops.example.com/g1t/budget",
5852− "state": "ok",
5853− "message": null
5854− },
5855− "notes": "All amounts are whole millionths of a dollar: 500000000 is $500. `max_amount_micros` is null for g1t's own workspaces, which have no ceiling. When `state` is `stopped`, new sandboxes, builds and app requests wait until the limit is raised or the month closes."
5856− },
5857− "set_budget": {
5858− "params": {
5859− "workspace": "flagon-io"
5860− },
5861− "request": {
5862− "amount_micros": 500000000,
5863− "alerts": [
5864− 50,
5865− 75,
5866− 90,
5867− 100
5868− ],
5869− "webhook": "https://ops.example.com/g1t/budget"
5870− },
5871− "response": {
5872− "workspace": "flagon-io",
5873− "amount_micros": 500000000,
5874− "automatic": false,
5875− "spent_micros": 132450000,
5876− "max_amount_micros": 2000000000,
5877− "alerts": [
5878− 50,
5879− 75,
5880− 90,
5881− 100
5882− ],
5883− "pause_at_limit": true,
5884− "webhook": "https://ops.example.com/g1t/budget",
5885− "state": "ok",
5886− "message": null
5887− },
5888− "notes": "Fields left out keep their value. A limit above `max_amount_micros` is refused with `invalid`. Called by anyone but an owner signed in as a person, or by a workspace's own token or one of g1t's agents, it is refused with `forbidden`. Each alert is sent once a month, to the owners by email and, with `webhook`, as a JSON POST."
5889− },
5890− "get_ai_credit": {
5891− "params": {
5892− "workspace": "flagon-io"
5893− },
5894− "response": {
5895− "balance_micros": 62000000,
5896− "purchased_micros": 50000000,
5897− "given_micros": 12000000,
5898− "grants": [
5899− {
5900− "id": "crd_01kkr2m4c8f1t7qh3d6n9w5p0x",
5901− "workspace": "flagon-io",
5902− "kind": "purchase",
5903− "amount_micros": 50000000,
5904− "used_micros": 0,
5905− "left_micros": 50000000,
5906− "note": "AI credit bought",
5907− "refund_for": null,
5908− "refund_day": null,
5909− "expires_at": "2027-10-02T00:00:00.000Z",
5910− "created_by": "ana",
5911− "created_at": "2026-10-02T16:20:00.000Z",
5912− "state": "open",
5913− "closed_at": null,
5914− "closed_note": null,
5915− "closed_by": null
5916− }
5917− ],
5918− "free_via_discount": false,
5919− "postpaid": false,
5920− "blocked": false,
5921− "can_buy": true,
5922− "presets_cents": [
5923− 2500,
5924− 5000,
5925− 10000,
5926− 25000
5927− ],
5928− "min_cents": 1000,
5929− "max_cents": 100000,
5930− "card_fee": {
5931− "on": true,
5932− "percent_micros": 29000,
5933− "fixed_cents": 30
5934− },
5935− "reload": {
5936− "enabled": false,
5937− "threshold_micros": 10000000,
5938− "target_micros": 50000000,
5939− "monthly_max_micros": 200000000,
5940− "reloaded_micros": 0,
5941− "failed_at": null,
5942− "error": null
5943− },
5944− "agent_rate_micros": 3.6,
5945− "model_markup_percent": 10,
5946− "gateway_markup_percent": 5,
5947− "upgrade_credit_micros": 10000000,
5948− "expires_days": 365
5949− },
5950− "notes": "`card_fee.percent_micros` is per dollar charged, in millionths: 29000 is 2.9%. `blocked` is true when the credit has run out and new runs on g1t's models wait for more; runs on a model provider the workspace connected itself never need it."
5951− },
5952− "buy_ai_credit": {
5953− "params": {
5954− "workspace": "flagon-io"
5955− },
5956− "request": {
5957− "amount_cents": 5000
5958− },
5959− "response": {
5960− "url": "https://checkout.example.com/c/pay/cs_test_a1b2c3"
5961− },
5962− "notes": "Open `url` in a browser to pay. Nothing is charged until the payment is made there; the credit then shows in get_ai_credit. An amount outside `min_cents` to `max_cents`, or not in whole dollars, is refused with `invalid`; a workspace that cannot buy credit (see `can_buy`) gets `conflict` or `payment_required`."
5963− },
5964− "list_invoices": {
5965− "params": {
5966− "workspace": "flagon-io"
5967− },
5968− "response": {
5969− "invoices": [
5970− {
5971− "id": "in_1Q2w3E4r5T6y7U8i",
5972− "number": "FLAGON-0004",
5973− "status": "paid",
5974− "total_cents": 4210,
5975− "currency": "usd",
5976− "created_at": "2026-10-01T00:05:00.000Z",
5977− "description": "Usage for 2026-09",
5978− "hosted_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i",
5979− "pdf_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i/pdf"
5980− }
5981− ],
5982− "usage_invoices": [
5983− {
5984− "id": "inv_01kkqz8d3c6f9t2wq5n8h1m4r7",
5985− "workspace": "flagon-io",
5986− "reason": "month",
5987− "period": "2026-09",
5988− "amount_micros": 42100000,
5989− "status": "paid",
5990− "hosted_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i",
5991− "pdf_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i/pdf",
5992− "lines": [
5993− {
5994− "description": "Agent: models",
5995− "amount_micros": 35900000
5996− },
5997− {
5998− "description": "Sandbox time",
5999− "amount_micros": 6200000
6000− }
6001− ],
6002− "created_at": "2026-10-01T00:05:00.000Z"
6003− }
6004− ],
6005− "upcoming": {
6006− "closes_at": "2026-11-01T00:00:00.000Z",
6007− "subscriptions_micros": 20000000,
6008− "usage_micros": 10210000,
6009− "total_micros": 30210000
6010− },
6011− "unavailable": null
6012− },
6013− "notes": "`invoices` are in cents (`total_cents`); `usage_invoices` and `upcoming` in millionths of a dollar. A usage invoice's `reason` is `month` (the month closed) or `threshold` (charged near the limit), and its `status` `paid`, `open`, `failed` or `void`. An invoice's `status` is `paid`, `open`, `void`, `uncollectible` or `draft`."
6014− },
6015− "get_billing_details": {
6016− "params": {
6017− "workspace": "flagon-io"
6018− },
6019− "response": {
6020− "customer": true,
6021− "email": "billing@flagon.example.com",
6022− "name": "Flagon, Inc.",
6023− "address": {
6024− "line1": "100 Market Street",
6025− "line2": "",
6026− "city": "San Francisco",
6027− "state": "CA",
6028− "postal_code": "94105",
6029− "country": "US"
6030− },
6031− "tax_id_type": "us_ein",
6032− "tax_id": "12-3456789",
6033− "po_number": null,
6034− "language": "en",
6035− "payment_method": {
6036− "kind": "card",
6037− "brand": "visa",
6038− "last4": "4242",
6039− "exp_month": 12,
6040− "exp_year": 2028
6041− }
6042− },
6043− "notes": "Owners change these on the workspace's billing page. `payment_method` is null until a card or other way to pay is saved."
6044− },
6045− "list_pinned_projects": {
6046− "params": {
6047− "workspace": "flagon-io"
6048− },
6049− "response": [
6050− {
6051− "position": 0,
6052− "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6053− "workspace": "flagon-io",
6054− "slug": "g1t",
6055− "name": "g1t",
6056− "description": null,
6057− "private": false,
6058− "archived": false,
6059− "kind": "app",
6060− "url": "https://g1t.sh/flagon-io/g1t",
6061− "pushed_at": "2026-10-07T10:00:00.000Z",
6062− "updated_at": "2026-10-01T09:12:00.000Z"
6063− },
6064− {
6065− "position": 1,
6066− "id": "prj_01kkq0c4d9h2w7rn5f8t3k6p2z",
6067− "workspace": "flagon-io",
6068− "slug": "lab-api",
6069− "name": "lab-api",
6070− "description": null,
6071− "private": true,
6072− "archived": false,
6073− "kind": "app",
6074− "url": "https://g1t.sh/flagon-io/lab-api",
6075− "pushed_at": "2026-10-06T18:40:00.000Z",
6076− "updated_at": "2026-10-01T09:12:00.000Z"
6077− },
6078− {
6079− "position": 2,
6080− "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6081− "workspace": "flagon-io",
6082− "slug": "hello",
6083− "name": "hello",
6084− "description": "Greets people from the command line.",
6085− "private": false,
6086− "archived": false,
6087− "kind": "library",
6088− "url": "https://g1t.sh/flagon-io/hello",
6089− "pushed_at": null,
6090− "updated_at": "2026-10-01T09:12:00.000Z"
6091− }
6092− ],
6093− "notes": "In your order: `position` 0 first. The sidebar shows these, then the projects you opened last. `pushed_at` is null until the project's repository is pushed to."
6094− },
6095− "pin_project": {
6096− "params": {
6097− "workspace": "flagon-io",
6098− "project": "hello"
6099− },
6100− "request": {
6101− "position": 0
6102− },
6103− "response": [
6104− {
6105− "position": 0,
6106− "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6107− "workspace": "flagon-io",
6108− "slug": "hello",
6109− "name": "hello",
6110− "description": "Greets people from the command line.",
6111− "private": false,
6112− "archived": false,
6113− "kind": "library",
6114− "url": "https://g1t.sh/flagon-io/hello",
6115− "pushed_at": null,
6116− "updated_at": "2026-10-01T09:12:00.000Z"
6117− },
6118− {
6119− "position": 1,
6120− "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6121− "workspace": "flagon-io",
6122− "slug": "g1t",
6123− "name": "g1t",
6124− "description": null,
6125− "private": false,
6126− "archived": false,
6127− "kind": "app",
6128− "url": "https://g1t.sh/flagon-io/g1t",
6129− "pushed_at": "2026-10-07T10:00:00.000Z",
6130− "updated_at": "2026-10-01T09:12:00.000Z"
6131− },
6132− {
6133− "position": 2,
6134− "id": "prj_01kkq0c4d9h2w7rn5f8t3k6p2z",
6135− "workspace": "flagon-io",
6136− "slug": "lab-api",
6137− "name": "lab-api",
6138− "description": null,
6139− "private": true,
6140− "archived": false,
6141− "kind": "app",
6142− "url": "https://g1t.sh/flagon-io/lab-api",
6143− "pushed_at": "2026-10-06T18:40:00.000Z",
6144− "updated_at": "2026-10-01T09:12:00.000Z"
6145− }
6146− ],
6147− "notes": "A ninth pin in a workspace is refused with `409 conflict`: unpin one first."
6148− },
6149− "unpin_project": {
6150− "params": {
6151− "workspace": "flagon-io",
6152− "project": "lab-api"
6153− },
6154− "response": [
6155− {
6156− "position": 0,
6157− "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6158− "workspace": "flagon-io",
6159− "slug": "g1t",
6160− "name": "g1t",
6161− "description": null,
6162− "private": false,
6163− "archived": false,
6164− "kind": "app",
6165− "url": "https://g1t.sh/flagon-io/g1t",
6166− "pushed_at": "2026-10-07T10:00:00.000Z",
6167− "updated_at": "2026-10-01T09:12:00.000Z"
6168− },
6169− {
6170− "position": 1,
6171− "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6172− "workspace": "flagon-io",
6173− "slug": "hello",
6174− "name": "hello",
6175− "description": "Greets people from the command line.",
6176− "private": false,
6177− "archived": false,
6178− "kind": "library",
6179− "url": "https://g1t.sh/flagon-io/hello",
6180− "pushed_at": null,
6181− "updated_at": "2026-10-01T09:12:00.000Z"
6182− }
6183− ]
6184− },
6185− "reorder_pinned_projects": {
6186− "params": {
6187− "workspace": "flagon-io"
6188− },
6189− "request": {
6190− "projects": [
6191− "lab-api",
6192− "g1t",
6193− "hello"
6194− ]
6195− },
6196− "response": [
6197− {
6198− "position": 0,
6199− "id": "prj_01kkq0c4d9h2w7rn5f8t3k6p2z",
6200− "workspace": "flagon-io",
6201− "slug": "lab-api",
6202− "name": "lab-api",
6203− "description": null,
6204− "private": true,
6205− "archived": false,
6206− "kind": "app",
6207− "url": "https://g1t.sh/flagon-io/lab-api",
6208− "pushed_at": "2026-10-06T18:40:00.000Z",
6209− "updated_at": "2026-10-01T09:12:00.000Z"
6210− },
6211− {
6212− "position": 1,
6213− "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6214− "workspace": "flagon-io",
6215− "slug": "g1t",
6216− "name": "g1t",
6217− "description": null,
6218− "private": false,
6219− "archived": false,
6220− "kind": "app",
6221− "url": "https://g1t.sh/flagon-io/g1t",
6222− "pushed_at": "2026-10-07T10:00:00.000Z",
6223− "updated_at": "2026-10-01T09:12:00.000Z"
6224− },
6225− {
6226− "position": 2,
6227− "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6228− "workspace": "flagon-io",
6229− "slug": "hello",
6230− "name": "hello",
6231− "description": "Greets people from the command line.",
6232− "private": false,
6233− "archived": false,
6234− "kind": "library",
6235− "url": "https://g1t.sh/flagon-io/hello",
6236− "pushed_at": null,
6237− "updated_at": "2026-10-01T09:12:00.000Z"
6238− }
6239− ],
6240− "notes": "Name every pinned project once; anything else is refused with `422 invalid`."
6241− },
6242− "list_secret_scanning_alerts": {
6243− "params": {
6244− "owner": "flagon-io",
6245− "name": "hello"
6246− },
6247− "query": {
6248− "state": "open"
6249− },
6250− "response": [
6251− {
6252− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6253− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6254− "kind": "github_token",
6255− "label": "a GitHub token",
6256− "path": "scripts/release.sh",
6257− "line": 12,
6258− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6259− "preview": "ghp_X7…",
6260− "status": "open",
6261− "source": "push",
6262− "found_by": "syntaqx",
6263− "found_at": "2026-10-06T09:14:02.118Z",
6264− "decided_by": null,
6265− "reason": null,
6266− "decided_at": null,
6267− "dismissed_reason": null,
6268− "test_value": null,
6269− "state": "open",
6270− "validity": "active",
6271− "validity_checked_at": "2026-10-06T09:20:41.502Z",
6272− "bypass": {
6273− "reason": "will_fix_later",
6274− "comment": "Rotating it this afternoon.",
6275− "by": "syntaqx",
6276− "at": "2026-10-06T09:14:02.118Z",
6277− "approved_by": null
6278− },
6279− "pattern_id": null,
6280− "pattern_name": null,
6281− "locations": 1
6282− }
6283− ],
6284− "notes": "| Filter | Values |\n| --- | --- |\n| `state` | `open` (in the history, or blocked at a push), `dismissed`, `fixed` |\n| `secret_type` | `aws_access_key`, `github_token`, `custom_pattern`, … |\n| `validity` | `active`, `inactive`, `unknown`, `unsupported` |\n| `bypassed` | `true` or `false` |\n\nThe secret itself is never returned: `preview` is enough to recognise it. `status` says where it stands: `open`, `blocked` (stopped at a push, never landed), `allowed` or `resolved`."
6285− },
6286− "list_secret_scanning_alerts_for_workspace": {
6287− "params": {
6288− "workspace": "flagon-io"
6289− },
6290− "query": {
6291− "state": "open"
6292− },
6293− "response": [
6294− {
6295− "repo": "hello",
6296− "secret": {
6297− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6298− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6299− "kind": "github_token",
6300− "label": "a GitHub token",
6301− "path": "scripts/release.sh",
6302− "line": 12,
6303− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6304− "preview": "ghp_X7…",
6305− "status": "open",
6306− "source": "push",
6307− "found_by": "syntaqx",
6308− "found_at": "2026-10-06T09:14:02.118Z",
6309− "decided_by": null,
6310− "reason": null,
6311− "decided_at": null,
6312− "dismissed_reason": null,
6313− "test_value": null,
6314− "state": "open",
6315− "validity": "active",
6316− "validity_checked_at": "2026-10-06T09:20:41.502Z",
6317− "bypass": {
6318− "reason": "will_fix_later",
6319− "comment": "Rotating it this afternoon.",
6320− "by": "syntaqx",
6321− "at": "2026-10-06T09:14:02.118Z",
6322− "approved_by": null
6323− },
6324− "pattern_id": null,
6325− "pattern_name": null,
6326− "locations": 1
6327− }
6328− }
6329− ],
6330− "notes": "Every repository whose findings you may see, each alert with its repository's name."
6331− },
6332− "get_secret_scanning_alert": {
6333− "params": {
6334− "owner": "flagon-io",
6335− "name": "hello",
6336− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6337− },
6338− "response": {
6339− "secret": {
6340− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6341− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6342− "kind": "github_token",
6343− "label": "a GitHub token",
6344− "path": "scripts/release.sh",
6345− "line": 12,
6346− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6347− "preview": "ghp_X7…",
6348− "status": "blocked",
6349− "source": "push",
6350− "found_by": "syntaqx",
6351− "found_at": "2026-10-06T09:14:02.118Z",
6352− "decided_by": null,
6353− "reason": null,
6354− "decided_at": null,
6355− "dismissed_reason": null,
6356− "test_value": null,
6357− "state": "open",
6358− "validity": null,
6359− "validity_checked_at": null,
6360− "bypass": null,
6361− "pattern_id": null,
6362− "pattern_name": null,
6363− "locations": 1
6364− },
6365− "locations": [
6366− {
6367− "path": "scripts/release.sh",
6368− "line": 12,
6369− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6370− "source": "push",
6371− "found_at": "2026-10-06T09:14:02.118Z"
6372− }
6373− ],
6374− "activity": [],
6375− "requests": [],
6376− "checkable": true,
6377− "can_bypass": true,
6378− "can_request_bypass": false
6379− }
6380− },
6381− "update_secret_scanning_alert": {
6382− "params": {
6383− "owner": "flagon-io",
6384− "name": "hello",
6385− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6386− },
6387− "request": {
6388− "state": "dismissed",
6389− "reason": "revoked",
6390− "comment": "Rotated in the issuer's settings."
6391− },
6392− "response": {
6393− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6394− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6395− "kind": "github_token",
6396− "label": "a GitHub token",
6397− "path": "scripts/release.sh",
6398− "line": 12,
6399− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6400− "preview": "ghp_X7…",
6401− "status": "resolved",
6402− "source": "push",
6403− "found_by": "syntaqx",
6404− "found_at": "2026-10-06T09:14:02.118Z",
6405− "decided_by": "syntaqx",
6406− "reason": "Rotated in the issuer's settings.",
6407− "decided_at": "2026-10-06T09:20:41.502Z",
6408− "dismissed_reason": "revoked",
6409− "test_value": null,
6410− "state": "fixed",
6411− "validity": "active",
6412− "validity_checked_at": "2026-10-06T09:20:41.502Z",
6413− "bypass": {
6414− "reason": "will_fix_later",
6415− "comment": "Rotating it this afternoon.",
6416− "by": "syntaqx",
6417− "at": "2026-10-06T09:14:02.118Z",
6418− "approved_by": null
6419− },
6420− "pattern_id": null,
6421− "pattern_name": null,
6422− "locations": 1
6423− },
6424− "notes": "Takes the Admin role: a dismissed secret is let through push protection, unless it was `revoked`, which marks it fixed. `state` `open` reopens it."
6425− },
6426− "list_secret_scanning_locations": {
6427− "params": {
6428− "owner": "flagon-io",
6429− "name": "hello",
6430− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6431− },
6432− "response": [
6433− {
6434− "path": "scripts/release.sh",
6435− "line": 12,
6436− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6437− "source": "push",
6438− "found_at": "2026-10-06T09:14:02.118Z"
6439− }
6440− ]
6441− },
6442− "bypass_push_protection": {
6443− "params": {
6444− "owner": "flagon-io",
6445− "name": "hello",
6446− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6447− },
6448− "request": {
6449− "reason": "will_fix_later",
6450− "comment": "Rotating it this afternoon."
6451− },
6452− "response": {
6453− "secret": {
6454− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6455− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6456− "kind": "github_token",
6457− "label": "a GitHub token",
6458− "path": "scripts/release.sh",
6459− "line": 12,
6460− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6461− "preview": "ghp_X7…",
6462− "status": "open",
6463− "source": "push",
6464− "found_by": "syntaqx",
6465− "found_at": "2026-10-06T09:14:02.118Z",
6466− "decided_by": null,
6467− "reason": null,
6468− "decided_at": null,
6469− "dismissed_reason": null,
6470− "test_value": null,
6471− "state": "open",
6472− "validity": null,
6473− "validity_checked_at": null,
6474− "bypass": {
6475− "reason": "will_fix_later",
6476− "comment": "Rotating it this afternoon.",
6477− "by": "syntaqx",
6478− "at": "2026-10-06T09:14:02.118Z",
6479− "approved_by": null
6480− },
6481− "pattern_id": null,
6482− "pattern_name": null,
6483− "locations": 1
6484− },
6485− "request": null
6486− },
6487− "notes": "| Reason | The alert |\n| --- | --- |\n| `false_positive` | Closed as a false positive |\n| `used_in_tests` | Closed as used in tests |\n| `will_fix_later` | Stays open, to be rotated |\n\nWith delegated bypass on, a call from someone who does not review bypasses makes a request instead: `request` is set and the secret is still blocked until an owner or admin approves it. Push again once it is bypassed."
6488− },
6489− "check_secret_validity": {
6490− "params": {
6491− "owner": "flagon-io",
6492− "name": "hello",
6493− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6494− },
6495− "response": {
6496− "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6497− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6498− "kind": "github_token",
6499− "label": "a GitHub token",
6500− "path": "scripts/release.sh",
6501− "line": 12,
6502− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6503− "preview": "ghp_X7…",
6504− "status": "open",
6505− "source": "push",
6506− "found_by": "syntaqx",
6507− "found_at": "2026-10-06T09:14:02.118Z",
6508− "decided_by": null,
6509− "reason": null,
6510− "decided_at": null,
6511− "dismissed_reason": null,
6512− "test_value": null,
6513− "state": "open",
6514− "validity": "active",
6515− "validity_checked_at": "2026-10-06T09:20:41.502Z",
6516− "bypass": {
6517− "reason": "will_fix_later",
6518− "comment": "Rotating it this afternoon.",
6519− "by": "syntaqx",
6520− "at": "2026-10-06T09:14:02.118Z",
6521− "approved_by": null
6522− },
6523− "pattern_id": null,
6524− "pattern_name": null,
6525− "locations": 1
6526− },
6527− "notes": "Made for GitHub, GitLab, Stripe, Slack, npm, OpenAI, Anthropic and SendGrid tokens, with the issuer's own read-only call. Other formats answer `unsupported`; a secret that never landed answers `unknown`."
6528− },
6529− "list_bypass_requests": {
6530− "params": {
6531− "workspace": "flagon-io"
6532− },
6533− "query": {
6534− "state": "pending"
6535− },
6536− "response": [
6537− {
6538− "id": "byp_01kq2n8e5f6g7h8j9k0m1n2p3q",
6539− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6540− "workspace": "flagon-io",
6541− "repo": "hello",
6542− "secret_id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6543− "label": "a GitHub token",
6544− "path": "scripts/release.sh",
6545− "line": 12,
6546− "preview": "ghp_X7…",
6547− "requester": "ana",
6548− "reason": "used_in_tests",
6549− "comment": "A token from the test fixtures, never issued.",
6550− "state": "pending",
6551− "reviewer": null,
6552− "review_comment": null,
6553− "created_at": "2026-10-06T09:14:02.118Z",
6554− "reviewed_at": null
6555− }
6556− ]
6557− },
6558− "review_bypass_request": {
6559− "params": {
6560− "workspace": "flagon-io",
6561− "id": "byp_01kq2n8e5f6g7h8j9k0m1n2p3q"
6562− },
6563− "request": {
6564− "decision": "approve",
6565− "comment": "A fixture."
6566− },
6567− "response": {
6568− "id": "byp_01kq2n8e5f6g7h8j9k0m1n2p3q",
6569− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6570− "workspace": "flagon-io",
6571− "repo": "hello",
6572− "secret_id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6573− "label": "a GitHub token",
6574− "path": "scripts/release.sh",
6575− "line": 12,
6576− "preview": "ghp_X7…",
6577− "requester": "ana",
6578− "reason": "used_in_tests",
6579− "comment": "A token from the test fixtures, never issued.",
6580− "state": "approved",
6581− "reviewer": "syntaqx",
6582− "review_comment": "A fixture.",
6583− "created_at": "2026-10-06T09:14:02.118Z",
6584− "reviewed_at": "2026-10-06T09:20:41.502Z"
6585− }
6586− },
6587− "list_custom_patterns": {
6588− "params": {
6589− "owner": "flagon-io",
6590− "name": "hello"
6591− },
6592− "response": {
6593− "patterns": [
6594− {
6595− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6596− "scope": "repository",
6597− "workspace": "flagon-io",
6598− "repo": "hello",
6599− "name": "Acme API key",
6600− "pattern": "acme_[a-z0-9]{32}",
6601− "before": null,
6602− "after": null,
6603− "test_strings": [
6604− "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6605− ],
6606− "state": "published",
6607− "created_by": "syntaqx",
6608− "created_at": "2026-10-06T09:14:02.118Z",
6609− "updated_by": "syntaqx",
6610− "updated_at": "2026-10-06T09:14:02.118Z",
6611− "open_alerts": 0
6612− }
6613− ],
6614− "entitled": true
6615− },
6616− "notes": "A repository's list includes its workspace's patterns, with `scope` `workspace`. `entitled` says whether they run here: always on a public repository, and on a private one with the Security and quality activation."
6617− },
6618− "list_custom_patterns_for_workspace": {
6619− "params": {
6620− "workspace": "flagon-io"
6621− },
6622− "response": {
6623− "patterns": [
6624− {
6625− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6626− "scope": "workspace",
6627− "workspace": "flagon-io",
6628− "repo": null,
6629− "name": "Acme API key",
6630− "pattern": "acme_[a-z0-9]{32}",
6631− "before": null,
6632− "after": null,
6633− "test_strings": [
6634− "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6635− ],
6636− "state": "published",
6637− "created_by": "syntaqx",
6638− "created_at": "2026-10-06T09:14:02.118Z",
6639− "updated_by": "syntaqx",
6640− "updated_at": "2026-10-06T09:14:02.118Z",
6641− "open_alerts": 0
6642− }
6643− ],
6644− "entitled": true
6645− }
6646− },
6647− "create_custom_pattern": {
6648− "params": {
6649− "owner": "flagon-io",
6650− "name": "hello"
6651− },
6652− "request": {
6653− "pattern_name": "Acme API key",
6654− "pattern": "acme_[a-z0-9]{32}",
6655− "test_strings": [
6656− "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6657− ],
6658− "publish": true
6659− },
6660− "response": {
6661− "pattern": {
6662− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6663− "scope": "repository",
6664− "workspace": "flagon-io",
6665− "repo": "hello",
6666− "name": "Acme API key",
6667− "pattern": "acme_[a-z0-9]{32}",
6668− "before": null,
6669− "after": null,
6670− "test_strings": [
6671− "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6672− ],
6673− "state": "published",
6674− "created_by": "syntaqx",
6675− "created_at": "2026-10-06T09:14:02.118Z",
6676− "updated_by": "syntaqx",
6677− "updated_at": "2026-10-06T09:14:02.118Z",
6678− "open_alerts": 0
6679− },
6680− "tests": [
6681− [
6682− 9,
6683− 46
6684− ]
6685− ]
6686− },
6687− "notes": "`tests` gives, for each test string, where the pattern matched (start and end, in characters), or `null`. A pattern that does not compile, matches an empty string, or is too complex is refused with `422` and says why."
6688− },
6689− "create_custom_pattern_for_workspace": {
6690− "params": {
6691− "workspace": "flagon-io"
6692− },
6693− "request": {
6694− "pattern_name": "Acme API key",
6695− "pattern": "acme_[a-z0-9]{32}",
6696− "publish": false
6697− },
6698− "response": {
6699− "pattern": {
6700− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6701− "scope": "workspace",
6702− "workspace": "flagon-io",
6703− "repo": null,
6704− "name": "Acme API key",
6705− "pattern": "acme_[a-z0-9]{32}",
6706− "before": null,
6707− "after": null,
6708− "test_strings": [],
6709− "state": "draft",
6710− "created_by": "syntaqx",
6711− "created_at": "2026-10-06T09:14:02.118Z",
6712− "updated_by": "syntaqx",
6713− "updated_at": "2026-10-06T09:14:02.118Z",
6714− "open_alerts": 0
6715− },
6716− "tests": []
6717− }
6718− },
6719− "update_custom_pattern": {
6720− "params": {
6721− "owner": "flagon-io",
6722− "name": "hello",
6723− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6724− },
6725− "request": {
6726− "pattern_name": "Acme API key",
6727− "pattern": "acme_[a-z0-9]{32,40}",
6728− "publish": true
6729− },
6730− "response": {
6731− "pattern": {
6732− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6733− "scope": "repository",
6734− "workspace": "flagon-io",
6735− "repo": "hello",
6736− "name": "Acme API key",
6737− "pattern": "acme_[a-z0-9]{32,40}",
6738− "before": null,
6739− "after": null,
6740− "test_strings": [
6741− "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6742− ],
6743− "state": "published",
6744− "created_by": "syntaqx",
6745− "created_at": "2026-10-06T09:14:02.118Z",
6746− "updated_by": "syntaqx",
6747− "updated_at": "2026-10-06T09:14:02.118Z",
6748− "open_alerts": 0
6749− },
6750− "tests": [
6751− [
6752− 9,
6753− 46
6754− ]
6755− ]
6756− }
6757− },
6758− "update_custom_pattern_for_workspace": {
6759− "params": {
6760− "workspace": "flagon-io",
6761− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6762− },
6763− "request": {
6764− "pattern_name": "Acme API key",
6765− "pattern": "acme_[a-z0-9]{32}",
6766− "publish": true
6767− },
6768− "response": {
6769− "pattern": {
6770− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6771− "scope": "workspace",
6772− "workspace": "flagon-io",
6773− "repo": null,
6774− "name": "Acme API key",
6775− "pattern": "acme_[a-z0-9]{32}",
6776− "before": null,
6777− "after": null,
6778− "test_strings": [
6779− "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6780− ],
6781− "state": "published",
6782− "created_by": "syntaqx",
6783− "created_at": "2026-10-06T09:14:02.118Z",
6784− "updated_by": "syntaqx",
6785− "updated_at": "2026-10-06T09:14:02.118Z",
6786− "open_alerts": 0
6787− },
6788− "tests": [
6789− [
6790− 9,
6791− 46
6792− ]
6793− ]
6794− }
6795− },
6796− "delete_custom_pattern": {
6797− "params": {
6798− "owner": "flagon-io",
6799− "name": "hello",
6800− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6801− },
6802− "response": {
6803− "deleted": true
6804− }
6805− },
6806− "delete_custom_pattern_for_workspace": {
6807− "params": {
6808− "workspace": "flagon-io",
6809− "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6810− },
6811− "response": {
6812− "deleted": true
6813− }
6814− },
6815− "dry_run_custom_pattern": {
6816− "params": {
6817− "owner": "flagon-io",
6818− "name": "hello"
6819− },
6820− "request": {
6821− "pattern": "acme_[a-z0-9]{32}"
6822− },
6823− "response": {
6824− "repos": [
6825− {
6826− "name": "hello",
6827− "files_scanned": 214,
6828− "matches": [
6829− {
6830− "path": "config/dev.env",
6831− "line": 3,
6832− "preview": "ACME_KEY=acme_01••••••••••••••••••••••••"
6833− }
6834− ],
6835− "truncated": false,
6836− "commit": "4807077b296e6edbf410d55e72749d3e1170c291"
6837− }
6838− ]
6839− },
6840− "notes": "Reads up to 2,000 files and 20 MB of the default branch, skipping what secret scanning skips. Nothing is recorded."
6841− },
6842− "dry_run_custom_pattern_for_workspace": {
6843− "params": {
6844− "workspace": "flagon-io"
6845− },
6846− "request": {
6847− "pattern": "acme_[a-z0-9]{32}",
6848− "repos": [
6849− "hello"
6850− ]
6851− },
6852− "response": {
6853− "repos": [
6854− {
6855− "name": "hello",
6856− "files_scanned": 214,
6857− "matches": [],
6858− "truncated": false,
6859− "commit": "4807077b296e6edbf410d55e72749d3e1170c291"
6860− }
6861− ]
6862− }
6863− },
6864− "list_code_scanning_alerts": {
6865− "params": {
6866− "owner": "flagon-io",
6867− "name": "hello"
6868− },
6869− "query": {
6870− "state": "open",
6871− "severity": "high"
6872− },
6873− "response": [
6874− {
6875− "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
6876− "number": 4,
6877− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6878− "tool": "Semgrep OSS",
6879− "category": "Semgrep OSS",
6880− "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
6881− "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
6882− "rule_description": "Detected calls to child_process from a function argument.",
6883− "help": null,
6884− "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
6885− "tags": [
6886− "security",
6887− "CWE-78"
6888− ],
6889− "level": "error",
6890− "security_severity": null,
6891− "severity": "high",
6892− "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
6893− "path": "src/server.js",
6894− "start_line": 6,
6895− "end_line": 6,
6896− "start_column": 3,
6897− "end_column": 60,
6898− "state": "open",
6899− "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
6900− "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6901− "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6902− "created_at": "2026-10-06T09:14:02.118Z",
6903− "updated_at": "2026-10-06T09:14:02.118Z",
6904− "fixed_at": null,
6905− "dismissed_by": null,
6906− "dismissed_reason": null,
6907− "dismissed_comment": null,
6908− "dismissed_at": null,
6909− "issue": null
6910− }
6911− ],
6912− "notes": "`severity` is the rule's security severity when it has one (from its `security-severity` score), else from the result's level: `error` high, `warning` medium, `note` low."
6913− },
6914− "list_code_scanning_alerts_for_workspace": {
6915− "params": {
6916− "workspace": "flagon-io"
6917− },
6918− "query": {
6919− "state": "open"
6920− },
6921− "response": [
6922− {
6923− "repo": "hello",
6924− "code": {
6925− "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
6926− "number": 4,
6927− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6928− "tool": "Semgrep OSS",
6929− "category": "Semgrep OSS",
6930− "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
6931− "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
6932− "rule_description": "Detected calls to child_process from a function argument.",
6933− "help": null,
6934− "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
6935− "tags": [
6936− "security",
6937− "CWE-78"
6938− ],
6939− "level": "error",
6940− "security_severity": null,
6941− "severity": "high",
6942− "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
6943− "path": "src/server.js",
6944− "start_line": 6,
6945− "end_line": 6,
6946− "start_column": 3,
6947− "end_column": 60,
6948− "state": "open",
6949− "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
6950− "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6951− "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6952− "created_at": "2026-10-06T09:14:02.118Z",
6953− "updated_at": "2026-10-06T09:14:02.118Z",
6954− "fixed_at": null,
6955− "dismissed_by": null,
6956− "dismissed_reason": null,
6957− "dismissed_comment": null,
6958− "dismissed_at": null,
6959− "issue": null
6960− }
6961− }
6962− ]
6963− },
6964− "get_code_scanning_alert": {
6965− "params": {
6966− "owner": "flagon-io",
6967− "name": "hello",
6968− "number": 4
6969− },
6970− "response": {
6971− "alert": {
6972− "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
6973− "number": 4,
6974− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6975− "tool": "Semgrep OSS",
6976− "category": "Semgrep OSS",
6977− "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
6978− "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
6979− "rule_description": "Detected calls to child_process from a function argument.",
6980− "help": null,
6981− "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
6982− "tags": [
6983− "security",
6984− "CWE-78"
6985− ],
6986− "level": "error",
6987− "security_severity": null,
6988− "severity": "high",
6989− "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
6990− "path": "src/server.js",
6991− "start_line": 6,
6992− "end_line": 6,
6993− "start_column": 3,
6994− "end_column": 60,
6995− "state": "open",
6996− "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
6997− "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6998− "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6999− "created_at": "2026-10-06T09:14:02.118Z",
7000− "updated_at": "2026-10-06T09:14:02.118Z",
7001− "fixed_at": null,
7002− "dismissed_by": null,
7003− "dismissed_reason": null,
7004− "dismissed_comment": null,
7005− "dismissed_at": null,
7006− "issue": null
7007− },
7008− "activity": [],
7009− "analyses": [
7010− {
7011− "id": "ana_01kq2rbh8j9k0m1n2p3q4r5s6t",
7012− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7013− "sarif_id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7014− "tool": "Semgrep OSS",
7015− "tool_version": "1.140.0",
7016− "category": "Semgrep OSS",
7017− "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7018− "git_ref": "refs/heads/main",
7019− "pull": null,
7020− "results": 7,
7021− "new_alerts": 2,
7022− "fixed_alerts": 1,
7023− "dropped": 0,
7024− "created_at": "2026-10-06T09:14:02.118Z"
7025− }
7026− ]
7027− }
7028− },
7029− "update_code_scanning_alert": {
7030− "params": {
7031− "owner": "flagon-io",
7032− "name": "hello",
7033− "number": 4
7034− },
7035− "request": {
7036− "state": "dismissed",
7037− "dismissed_reason": "false_positive",
7038− "dismissed_comment": "The argument is a constant."
7039− },
7040− "response": {
7041− "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
7042− "number": 4,
7043− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7044− "tool": "Semgrep OSS",
7045− "category": "Semgrep OSS",
7046− "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
7047− "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
7048− "rule_description": "Detected calls to child_process from a function argument.",
7049− "help": null,
7050− "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
7051− "tags": [
7052− "security",
7053− "CWE-78"
7054− ],
7055− "level": "error",
7056− "security_severity": null,
7057− "severity": "high",
7058− "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
7059− "path": "src/server.js",
7060− "start_line": 6,
7061− "end_line": 6,
7062− "start_column": 3,
7063− "end_column": 60,
7064− "state": "dismissed",
7065− "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
7066− "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7067− "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7068− "created_at": "2026-10-06T09:14:02.118Z",
7069− "updated_at": "2026-10-06T09:14:02.118Z",
7070− "fixed_at": null,
7071− "dismissed_by": "syntaqx",
7072− "dismissed_reason": "false_positive",
7073− "dismissed_comment": "The argument is a constant.",
7074− "dismissed_at": "2026-10-06T09:20:41.502Z",
7075− "issue": null
7076− }
7077− },
7078− "list_code_scanning_analyses": {
7079− "params": {
7080− "owner": "flagon-io",
7081− "name": "hello"
7082− },
7083− "response": [
7084− {
7085− "id": "ana_01kq2rbh8j9k0m1n2p3q4r5s6t",
7086− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7087− "sarif_id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7088− "tool": "Semgrep OSS",
7089− "tool_version": "1.140.0",
7090− "category": "Semgrep OSS",
7091− "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7092− "git_ref": "refs/heads/main",
7093− "pull": null,
7094− "results": 7,
7095− "new_alerts": 2,
7096− "fixed_alerts": 1,
7097− "dropped": 0,
7098− "created_at": "2026-10-06T09:14:02.118Z"
7099− }
7100− ]
7101− },
7102− "upload_sarif": {
7103− "params": {
7104− "owner": "flagon-io",
7105− "name": "hello"
7106− },
7107− "request": {
7108− "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7109− "ref": "refs/heads/main",
7110− "sarif": "H4sIAAAAAAAA…",
7111− "checkout_uri": "file:///home/runner/work/repo"
7112− },
7113− "response": {
7114− "id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7115− "processing_status": "complete",
7116− "analyses": [
7117− "ana_01kq2rbh8j9k0m1n2p3q4r5s6t"
7118− ],
7119− "errors": [],
7120− "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7121− "git_ref": "refs/heads/main",
7122− "created_at": "2026-10-06T09:14:02.118Z"
7123− },
7124− "notes": "`sarif` is the SARIF 2.1.0 file gzipped, then base64-encoded: `gzip -c results.sarif | base64 -w0`. The upload is read at once: `processing_status` is `complete` or `failed`, with `errors` saying why. For `refs/pull/<number>/head`, the results become the pull request's `Code scanning` check instead of alerts."
7125− },
7126− "get_sarif_upload": {
7127− "params": {
7128− "owner": "flagon-io",
7129− "name": "hello",
7130− "id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v"
7131− },
7132− "response": {
7133− "id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7134− "processing_status": "complete",
7135− "analyses": [
7136− "ana_01kq2rbh8j9k0m1n2p3q4r5s6t"
7137− ],
7138− "errors": [],
7139− "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7140− "git_ref": "refs/heads/main",
7141− "created_at": "2026-10-06T09:14:02.118Z"
7142− }
7143− },
7144− "list_vulnerability_alerts": {
7145− "params": {
7146− "owner": "flagon-io",
7147− "name": "hello"
7148− },
7149− "query": {
7150− "state": "open"
7151− },
7152− "response": [
7153− {
7154− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7155− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7156− "ecosystem": "npm",
7157− "package": "lodash",
7158− "version": "4.17.20",
7159− "manifest": "package-lock.json",
7160− "advisory": "GHSA-35jh-r3h4-6jhm",
7161− "osv_id": "GHSA-35jh-r3h4-6jhm",
7162− "summary": "Command Injection in lodash",
7163− "severity": "high",
7164− "fixed_version": "4.17.21",
7165− "status": "open",
7166− "issue": null,
7167− "found_at": "2026-10-06T09:14:02.118Z",
7168− "fixed_at": null,
7169− "state": "open",
7170− "dismissed_by": null,
7171− "dismissed_reason": null,
7172− "dismissed_comment": null,
7173− "dismissed_at": null,
7174− "update": null
7175− }
7176− ]
7177− },
7178− "list_vulnerability_alerts_for_workspace": {
7179− "params": {
7180− "workspace": "flagon-io"
7181− },
7182− "query": {
7183− "severity": "critical"
7184− },
7185− "response": [
7186− {
7187− "repo": "hello",
7188− "vulnerability": {
7189− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7190− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7191− "ecosystem": "npm",
7192− "package": "lodash",
7193− "version": "4.17.20",
7194− "manifest": "package-lock.json",
7195− "advisory": "GHSA-35jh-r3h4-6jhm",
7196− "osv_id": "GHSA-35jh-r3h4-6jhm",
7197− "summary": "Command Injection in lodash",
7198− "severity": "high",
7199− "fixed_version": "4.17.21",
7200− "status": "open",
7201− "issue": null,
7202− "found_at": "2026-10-06T09:14:02.118Z",
7203− "fixed_at": null,
7204− "state": "open",
7205− "dismissed_by": null,
7206− "dismissed_reason": null,
7207− "dismissed_comment": null,
7208− "dismissed_at": null,
7209− "update": null
7210− }
7211− }
7212− ]
7213− },
7214− "get_vulnerability_alert": {
7215− "params": {
7216− "owner": "flagon-io",
7217− "name": "hello",
7218− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n"
7219− },
7220− "response": {
7221− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7222− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7223− "ecosystem": "npm",
7224− "package": "lodash",
7225− "version": "4.17.20",
7226− "manifest": "package-lock.json",
7227− "advisory": "GHSA-35jh-r3h4-6jhm",
7228− "osv_id": "GHSA-35jh-r3h4-6jhm",
7229− "summary": "Command Injection in lodash",
7230− "severity": "high",
7231− "fixed_version": "4.17.21",
7232− "status": "open",
7233− "issue": null,
7234− "found_at": "2026-10-06T09:14:02.118Z",
7235− "fixed_at": null,
7236− "state": "open",
7237− "dismissed_by": null,
7238− "dismissed_reason": null,
7239− "dismissed_comment": null,
7240− "dismissed_at": null,
7241− "update": null
7242− }
7243− },
7244− "update_vulnerability_alert": {
7245− "params": {
7246− "owner": "flagon-io",
7247− "name": "hello",
7248− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n"
7249− },
7250− "request": {
7251− "state": "dismissed",
7252− "reason": "tolerable_risk",
7253− "comment": "Only the build uses it."
7254− },
7255− "response": {
7256− "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7257− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7258− "ecosystem": "npm",
7259− "package": "lodash",
7260− "version": "4.17.20",
7261− "manifest": "package-lock.json",
7262− "advisory": "GHSA-35jh-r3h4-6jhm",
7263− "osv_id": "GHSA-35jh-r3h4-6jhm",
7264− "summary": "Command Injection in lodash",
7265− "severity": "high",
7266− "fixed_version": "4.17.21",
7267− "status": "dismissed",
7268− "issue": null,
7269− "found_at": "2026-10-06T09:14:02.118Z",
7270− "fixed_at": null,
7271− "state": "dismissed",
7272− "dismissed_by": "syntaqx",
7273− "dismissed_reason": "tolerable_risk",
7274− "dismissed_comment": "Only the build uses it.",
7275− "dismissed_at": "2026-10-06T09:20:41.502Z",
7276− "update": null
7277− }
7278− },
7279− "fix_security_alert": {
7280− "params": {
7281− "owner": "flagon-io",
7282− "name": "hello",
7283− "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s"
7284− },
7285− "response": {
7286− "issue": 57,
7287− "started": true,
7288− "message": null
7289− },
7290− "notes": "Opens an issue with what is wrong and what done means, and puts g1t on it as you. Its run is charged as agent usage, and its pull request lands through the repository's required checks. Asking again while the issue is open returns it."
7291− },
7292− "get_dependency_graph": {
7293− "params": {
7294− "owner": "flagon-io",
7295− "name": "hello"
7296− },
7297− "response": {
7298− "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7299− "manifests": [
7300− {
7301− "path": "package-lock.json",
7302− "ecosystem": "npm",
7303− "dependencies": 2,
7304− "direct": 1
7305− }
7306− ],
7307− "dependencies": [
7308− {
7309− "ecosystem": "npm",
7310− "name": "lodash",
7311− "version": "4.17.20",
7312− "manifest": "package-lock.json",
7313− "relationship": "direct",
7314− "development": false,
7315− "license": "MIT",
7316− "purl": "pkg:npm/lodash@4.17.20",
7317− "vulnerabilities": 1
7318− },
7319− {
7320− "ecosystem": "npm",
7321− "name": "ms",
7322− "version": "2.1.3",
7323− "manifest": "package-lock.json",
7324− "relationship": "transitive",
7325− "development": false,
7326− "license": "MIT",
7327− "purl": "pkg:npm/ms@2.1.3",
7328− "vulnerabilities": 0
7329− }
7330− ]
7331− }
7332− },
7333− "get_sbom": {
7334− "params": {
7335− "owner": "flagon-io",
7336− "name": "hello"
7337− },
7338− "response": {
7339− "sbom": {
7340− "spdxVersion": "SPDX-2.3",
7341− "dataLicense": "CC0-1.0",
7342− "SPDXID": "SPDXRef-DOCUMENT",
7343− "name": "flagon-io/hello dependency graph",
7344− "documentNamespace": "https://g1t.sh/flagon-io/hello/sbom/sbom_01kq2tdk0m1n2p3q4r5s6t7v8w",
7345− "creationInfo": {
7346− "created": "2026-10-06T09:14:02Z",
7347− "creators": [
7348− "Tool: g1t",
7349− "Organization: g1t"
7350− ],
7351− "comment": "Read from the repository's lockfiles on its default branch."
7352− },
7353− "documentDescribes": [
7354− "SPDXRef-Repository-flagon-io-hello"
7355− ],
7356− "packages": [
7357− {
7358− "SPDXID": "SPDXRef-Repository-flagon-io-hello",
7359− "name": "flagon-io/hello",
7360− "versionInfo": "4807077b296e6edbf410d55e72749d3e1170c291",
7361− "downloadLocation": "git+https://g1t.sh/flagon-io/hello.git",
7362− "filesAnalyzed": false,
7363− "licenseConcluded": "NOASSERTION",
7364− "licenseDeclared": "NOASSERTION",
7365− "copyrightText": "NOASSERTION",
7366− "primaryPackagePurpose": "SOURCE",
7367− "externalRefs": []
7368− },
7369− {
7370− "SPDXID": "SPDXRef-Package-npm-lodash-4.17.20",
7371− "name": "lodash",
7372− "versionInfo": "4.17.20",
7373− "downloadLocation": "NOASSERTION",
7374− "filesAnalyzed": false,
7375− "licenseConcluded": "NOASSERTION",
7376− "licenseDeclared": "MIT",
7377− "copyrightText": "NOASSERTION",
7378− "primaryPackagePurpose": "LIBRARY",
7379− "comment": "Resolved by package-lock.json (direct dependency).",
7380− "externalRefs": [
7381− {
7382− "referenceCategory": "PACKAGE-MANAGER",
7383− "referenceType": "purl",
7384− "referenceLocator": "pkg:npm/lodash@4.17.20"
7385− }
7386− ]
7387− }
7388− ],
7389− "relationships": [
7390− {
7391− "spdxElementId": "SPDXRef-DOCUMENT",
7392− "relationshipType": "DESCRIBES",
7393− "relatedSpdxElement": "SPDXRef-Repository-flagon-io-hello"
7394− },
7395− {
7396− "spdxElementId": "SPDXRef-Repository-flagon-io-hello",
7397− "relationshipType": "DEPENDS_ON",
7398− "relatedSpdxElement": "SPDXRef-Package-npm-lodash-4.17.20"
7399− }
7400− ]
7401− }
7402− },
7403− "notes": "`sbom` is an SPDX 2.3 JSON document, sent as SPDX spells it. Save it with `jq .sbom`."
7404− },
7405− "compare_dependencies": {
7406− "params": {
7407− "owner": "flagon-io",
7408− "name": "hello",
7409− "basehead": "main...upgrade-deps"
7410− },
7411− "response": {
7412− "base": "main",
7413− "head": "upgrade-deps",
7414− "changes": [
7415− {
7416− "change_type": "added",
7417− "manifest": "package-lock.json",
7418− "ecosystem": "npm",
7419− "name": "lodash",
7420− "version": "4.17.20",
7421− "relationship": "direct",
7422− "development": false,
7423− "license": "MIT",
7424− "purl": "pkg:npm/lodash@4.17.20",
7425− "vulnerabilities": [
7426− {
7427− "advisory": "GHSA-35jh-r3h4-6jhm",
7428− "osv_id": "GHSA-35jh-r3h4-6jhm",
7429− "summary": "Command Injection in lodash",
7430− "severity": "high",
7431− "fixed_version": "4.17.21",
7432− "url": "https://osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm"
7433− }
7434− ],
7435− "denied_license": false,
7436− "failing": true
7437− },
7438− {
7439− "change_type": "removed",
7440− "manifest": "package-lock.json",
7441− "ecosystem": "npm",
7442− "name": "lodash",
7443− "version": "4.17.21",
7444− "relationship": "direct",
7445− "development": false,
7446− "license": "MIT",
7447− "purl": "pkg:npm/lodash@4.17.21",
7448− "vulnerabilities": [],
7449− "denied_license": false,
7450− "failing": false
7451− }
7452− ],
7453− "passed": false,
7454− "headline": "Adds 1 vulnerable package",
7455− "fail_on": "high",
7456− "deny_licenses": []
7457− }
7458− },
7459− "get_security_settings": {
7460− "params": {
7461− "owner": "flagon-io",
7462− "name": "hello"
7463− },
7464− "response": {
7465− "settings": {
7466− "code_scanning_gate": "high",
7467− "dependency_review": true,
7468− "review_fail_on": "high",
7469− "review_deny_licenses": [
7470− "AGPL-3.0-only"
7471− ],
7472− "review_comment": true
7473− },
7474− "workspace": {
7475− "delegated_bypass": true,
7476− "validity_checks": true
7477− },
7478− "private": true,
7479− "entitled": true,
7480− "upkeep": true
7481− }
7482− },
7483− "update_security_settings": {
7484− "params": {
7485− "owner": "flagon-io",
7486− "name": "hello"
7487− },
7488− "request": {
7489− "code_scanning_gate": "high",
7490− "review_deny_licenses": [
7491− "AGPL-3.0-only"
7492− ]
7493− },
7494− "response": {
7495− "settings": {
7496− "code_scanning_gate": "high",
7497− "dependency_review": true,
7498− "review_fail_on": "high",
7499− "review_deny_licenses": [
7500− "AGPL-3.0-only"
7501− ],
7502− "review_comment": true
7503− },
7504− "workspace": {
7505− "delegated_bypass": true,
7506− "validity_checks": true
7507− },
7508− "private": true,
7509− "entitled": true,
7510− "upkeep": true
7511− },
7512− "notes": "Only what you send changes. The `Code scanning` and `Dependency review` checks gate merges once you require them in branch protection."
7513− },
7514− "get_workspace_security_settings": {
7515− "params": {
7516− "workspace": "flagon-io"
7517− },
7518− "response": {
7519− "settings": {
7520− "delegated_bypass": true,
7521− "validity_checks": true
7522− },
7523− "activated": true
7524− }
7525− },
7526− "update_workspace_security_settings": {
7527− "params": {
7528− "workspace": "flagon-io"
7529− },
7530− "request": {
7531− "delegated_bypass": true
7532− },
7533− "response": {
7534− "settings": {
7535− "delegated_bypass": true,
7536− "validity_checks": true
7537− },
7538− "activated": true
7539− }
7540− },
7541− "get_security_overview": {
7542− "params": {
7543− "workspace": "flagon-io"
7544− },
7545− "query": {
7546− "days": "30"
7547− },
7548− "response": {
7549− "activated": true,
7550− "private_hidden": 0,
7551− "totals": [
7552− {
7553− "alert_type": "secret_scanning",
7554− "open": {
7555− "critical": 1,
7556− "high": 0,
7557− "medium": 0,
7558− "low": 0,
7559− "unknown": 0
7560− },
7561− "opened": 2,
7562− "closed": 1
7563− },
7564− {
7565− "alert_type": "code_scanning",
7566− "open": {
7567− "critical": 0,
7568− "high": 3,
7569− "medium": 4,
7570− "low": 0,
7571− "unknown": 0
7572− },
7573− "opened": 7,
7574− "closed": 2
7575− },
7576− {
7577− "alert_type": "vulnerability",
7578− "open": {
7579− "critical": 0,
7580− "high": 1,
7581− "medium": 2,
7582− "low": 1,
7583− "unknown": 0
7584− },
7585− "opened": 3,
7586− "closed": 5
7587− }
7588− ],
7589− "trend": [
7590− {
7591− "day": "2026-10-05",
7592− "secret_scanning": 1,
7593− "code_scanning": 8,
7594− "vulnerability": 6
7595− },
7596− {
7597− "day": "2026-10-06",
7598− "secret_scanning": 1,
7599− "code_scanning": 7,
7600− "vulnerability": 4
7601− }
7602− ],
7603− "repos": [
7604− {
7605− "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7606− "name": "hello",
7607− "private": true,
7608− "custom_patterns": 1,
7609− "validity_checks": true,
7610− "code_scanning_at": "2026-10-06T09:14:02.118Z",
7611− "dependency_review": true,
7612− "security_updates": true,
7613− "lockfiles": 1,
7614− "secrets": {
7615− "critical": 1,
7616− "high": 0,
7617− "medium": 0,
7618− "low": 0,
7619− "unknown": 0
7620− },
7621− "code": {
7622− "critical": 0,
7623− "high": 3,
7624− "medium": 4,
7625− "low": 0,
7626− "unknown": 0
7627− },
7628− "vulnerabilities": {
7629− "critical": 0,
7630− "high": 1,
7631− "medium": 2,
7632− "low": 1,
7633− "unknown": 0
7634− }
7635− }
7636− ]
7637− }
7638− },
7639− "create_label": {
7640− "request": {
7641− "label": "area: cli",
7642− "color": "1d76db",
7643− "description": "The command-line tool"
7644− },
7645− "response": {
7646− "name": "area: cli",
7647− "color": "1d76db",
7648− "description": "The command-line tool",
7649− "issues": 0,
7650− "pulls": 0
7651− }
7652− },
7653− "update_label": {
7654− "params": {
7655− "label": "area: cli"
7656− },
7657− "request": {
7658− "new_name": "cli",
7659− "color": "0052cc"
7660− },
7661− "response": {
7662− "name": "cli",
7663− "color": "0052cc",
7664− "description": "The command-line tool",
7665− "issues": 3,
7666− "pulls": 1
7667− },
7668− "notes": "Renaming a label renames it on every issue and pull request that carries it."
7669− },
7670− "delete_label": {
7671− "params": {
7672− "label": "wontfix"
7673− },
7674− "response": true
7675− },
7676− "add_default_labels": {
7677− "response": [
7678− {
7679− "name": "bug",
7680− "color": "d73a4a",
7681− "description": "Something isn't working",
7682− "issues": 4,
7683− "pulls": 1
7684− },
7685− {
7686− "name": "documentation",
7687− "color": "0075ca",
7688− "description": "Improvements or additions to documentation",
7689− "issues": 0,
7690− "pulls": 0
7691− }
7692− ],
7693− "notes": "Every label the repository has afterwards, shortened here. Labels it already had are left as they were."
7694− },
7695− "list_issue_labels": {
7696− "response": [
7697− {
7698− "name": "bug",
7699− "color": "d73a4a",
7700− "description": "Something isn't working",
7701− "issues": 4,
7702− "pulls": 1
7703− },
7704− {
7705− "name": "help wanted",
7706− "color": "008672",
7707− "description": "Extra attention is needed",
7708− "issues": 1,
7709− "pulls": 0
7710− }
7711− ]
7712− },
7713− "add_issue_labels": {
7714− "request": {
7715− "labels": [
7716− "help wanted"
7717− ]
7718− },
7719− "response": [
7720− "bug",
7721− "help wanted"
7722− ],
7723− "notes": "Returns its labels now, by name."
7724− },
7725− "set_issue_labels": {
7726− "request": {
7727− "labels": [
7728− "bug"
7729− ]
7730− },
7731− "response": [
7732− "bug"
7733− ]
7734− },
7735− "remove_issue_labels": {
7736− "response": []
7737− },
7738− "remove_issue_label": {
7739− "params": {
7740− "label": "help wanted"
7741− },
7742− "response": [
7743− "bug"
7744− ]
7745− },
7746− "list_milestones": {
7747− "response": [
7748− {
7749− "number": 3,
7750− "title": "Launch",
7751− "description": "Everything that has to land before the launch on October 14.",
7752− "due_on": "2026-10-14",
7753− "state": "open",
7754− "open_items": 5,
7755− "closed_items": 12,
7756− "created_at": "2026-09-20T09:00:00.000Z",
7757− "updated_at": "2026-10-06T16:12:40.118Z",
7758− "closed_at": null
7759− }
7760− ],
7761− "notes": "Open milestones soonest due first, then closed ones. Progress is closed_items out of open_items plus closed_items."
7762− },
7763− "create_milestone": {
7764− "request": {
7765− "title": "Launch",
7766− "description": "Everything that has to land before the launch on October 14.",
7767− "due_on": "2026-10-14"
7768− },
7769− "response": {
7770− "number": 3,
7771− "title": "Launch",
7772− "description": "Everything that has to land before the launch on October 14.",
7773− "due_on": "2026-10-14",
7774− "state": "open",
7775− "open_items": 0,
7776− "closed_items": 0,
7777− "created_at": "2026-09-20T09:00:00.000Z",
7778− "updated_at": "2026-09-20T09:00:00.000Z",
7779− "closed_at": null
7780− }
7781− },
7782− "update_milestone": {
7783− "params": {
7784− "milestone": 3
7785− },
7786− "request": {
7787− "state": "closed"
7788− },
7789− "response": {
7790− "number": 3,
7791− "title": "Launch",
7792− "description": "Everything that has to land before the launch on October 14.",
7793− "due_on": "2026-10-14",
7794− "state": "closed",
7795− "open_items": 0,
7796− "closed_items": 17,
7797− "created_at": "2026-09-20T09:00:00.000Z",
7798− "updated_at": "2026-10-14T18:00:00.000Z",
7799− "closed_at": "2026-10-14T18:00:00.000Z"
7800− }
7801− },
7802− "delete_milestone": {
7803− "params": {
7804− "milestone": 3
7805− },
7806− "response": true
7807− },
7808− "get_milestone": {
7809− "params": {
7810− "milestone": 3
7811− },
7812− "response": {
7813− "milestone": {
7814− "number": 3,
7815− "title": "Launch",
7816− "description": "Everything that has to land before the launch on October 14.",
7817− "due_on": "2026-10-14",
7818− "state": "open",
7819− "open_items": 5,
7820− "closed_items": 12,
7821− "created_at": "2026-09-20T09:00:00.000Z",
7822− "updated_at": "2026-10-06T16:12:40.118Z",
7823− "closed_at": null
7824− },
7825− "issues": [
7826− {
7827− "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
7828− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
7829− "number": 12,
7830− "title": "Greeting should name the caller",
7831− "body": "Take a name from the first argument; fall back to world.",
7832− "labels": [
7833− "feature",
7834− "good first issue"
7835− ],
7836− "state": "open",
7837− "reason": null,
7838− "resolved_by": null,
7839− "author": {
7840− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
7841− "username": "syntaqx",
7842− "kind": "user",
7843− "verified": false,
7844− "workspaces": []
7845− },
7846− "requested_by": null,
7847− "created_at": "2026-10-01T18:04:11.482Z",
7848− "updated_at": "2026-10-01T18:09:47.305Z",
7849− "closed_at": null,
7850− "pull_count": 0,
7851− "comment_count": 0,
7852− "assignees": [
7853− "syntaqx"
7854− ],
7855− "blocked_by": [],
7856− "queued": false,
7857− "agent": null,
7858− "milestone": {
7859− "number": 3,
7860− "title": "Launch"
7861− }
7862− }
7863− ],
7864− "pulls": [
7865− {
7866− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
7867− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
7868− "number": 14,
7869− "issue": 12,
7870− "title": "Greeting should name the caller",
7871− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
7872− "agent": "claude-code",
7873− "runtime": "external",
7874− "status": "open",
7875− "fork": {
7876− "namespace": "pulls",
7877− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
7878− },
7879− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
7880− "branch": null,
7881− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
7882− "merge_base": null,
7883− "merged_by": null,
7884− "merged_at": null,
7885− "superseded_by": null,
7886− "check_status": "passed",
7887− "files": [
7888− {
7889− "path": "src/main.rs",
7890− "additions": 6,
7891− "deletions": 2
7892− }
7893− ],
7894− "assignees": [],
7895− "reviewers": [
7896− "ana"
7897− ],
7898− "labels": [],
7899− "milestone": {
7900− "number": 3,
7901− "title": "Launch"
7902− },
7903− "base": "main",
7904− "author": {
7905− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
7906− "username": "syntaqx",
7907− "kind": "user",
7908− "verified": false,
7909− "workspaces": []
7910− },
7911− "requested_by": null,
7912− "created_at": "2026-10-01T18:20:02.117Z",
7913− "updated_at": "2026-10-01T18:35:44.902Z",
7914− "confidence": null
7915− }
7916− ]
7917− }
7918− },
7919− "update_pull_request": {
7920− "request": {
7921− "base": "release/1.x",
7922− "labels": [
7923− "bug"
7924− ]
7925− },
7926− "response": {
7927− "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
7928− "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
7929− "number": 14,
7930− "issue": 12,
7931− "title": "Greeting should name the caller",
7932− "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
7933− "agent": "claude-code",
7934− "runtime": "external",
7935− "status": "open",
7936− "fork": {
7937− "namespace": "pulls",
7938− "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
7939− },
7940− "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
7941− "branch": null,
7942− "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
7943− "merge_base": null,
7944− "merged_by": null,
7945− "merged_at": null,
7946− "superseded_by": null,
7947− "check_status": "passed",
7948− "files": [
7949− {
7950− "path": "src/main.rs",
7951− "additions": 6,
7952− "deletions": 2
7953− }
7954− ],
7955− "assignees": [],
7956− "reviewers": [
7957− "ana"
7958− ],
7959− "labels": [
7960− "bug"
7961− ],
7962− "milestone": null,
7963− "base": "release/1.x",
7964− "author": {
7965− "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
7966− "username": "syntaqx",
7967− "kind": "user",
7968− "verified": false,
7969− "workspaces": []
7970− },
7971− "requested_by": null,
7972− "created_at": "2026-10-01T18:20:02.117Z",
7973− "updated_at": "2026-10-01T18:35:44.902Z",
7974− "confidence": null
7975− },
7976− "notes": "A new base takes it out of the merge queue, and whether it is behind, merges cleanly and has the checks it needs is worked out against the new base."
7977− }
2+ "device_code": {
3+ "request": {
4+ "client_name": "Claude Code"
5+ },
6+ "response": {
7+ "device_code": "Gm3k…",
8+ "user_code": "WDJB-MJHT",
9+ "verification_uri": "https://g1t.sh/device",
10+ "verification_uri_complete": "https://g1t.sh/device?code=WDJB-MJHT",
11+ "expires_in": 900,
12+ "interval": 5
13+ }
14+ },
15+ "device_token": {
16+ "request": {
17+ "device_code": "Gm3k…"
18+ },
19+ "response": {
20+ "status": "approved",
21+ "token": "g1t_…",
22+ "username": "syntaqx",
23+ "verified": true
24+ }
25+ },
26+ "whoami": {
27+ "response": {
28+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
29+ "username": "syntaqx",
30+ "kind": "user",
31+ "verified": true,
32+ "workspaces": [
33+ {
34+ "slug": "acme",
35+ "role": "member",
36+ "base_permission": "write"
37+ },
38+ {
39+ "slug": "flagon-io",
40+ "role": "owner",
41+ "base_permission": "write"
42+ }
43+ ],
44+ "token": {
45+ "token_id": "tok_01kkntd3p2v8x6ym5r0c1q7a9e",
46+ "scopes": [
47+ "repo:read",
48+ "issues:read",
49+ "issues:write",
50+ "pull_requests:read",
51+ "pull_requests:write"
52+ ]
53+ }
54+ },
55+ "notes": "`token` is what the access token you called with may do: its `scopes` (left out for full access) and `legacy` when it was made before tokens had scopes. A token reaches every workspace and repository whoever it acts as can; its scopes say what it may do there. See [Scopes](/guides/authentication/#scopes). `kind` is `user`, `workspace` for a [workspace access token](/guides/workspaces/#workspace-access-tokens), or `agent` for the token a g1t agent works with. For a workspace token, `username` is the workspace's slug and `workspaces` holds only that workspace. Each workspace carries its `base_permission`: what a member gets on each of its repositories (owners have Admin). Roles given on single repositories are in `grants`, each with `repo_id`, `workspace` and `role`; it is left out when there are none. See [Access and roles](/guides/access-and-roles/)."
56+ },
57+ "create_workspace": {
58+ "request": {
59+ "slug": "acme-labs",
60+ "name": "Acme Labs"
61+ },
62+ "response": {
63+ "id": "wsp_01m43teqa9em6bje0bhvdj4jkb",
64+ "slug": "acme-labs",
65+ "name": "Acme Labs",
66+ "description": null,
67+ "created_at": "2026-10-04T16:02:51.337Z",
68+ "member_count": 1,
69+ "base_permission": "write",
70+ "team_creation": "members"
71+ },
72+ "notes": "`base_permission` is what every member gets on each of its repositories: `write` until an owner changes it with `PATCH /workspaces/{workspace}` or `PUT /workspaces/{workspace}/base_permission`. See [Access and roles](/guides/access-and-roles/). `team_creation` is who may create its teams: `members` (any member) until an owner sets `owners` with `PATCH /workspaces/{workspace}`. A new workspace is free, and each person owns at most one free workspace: while you own one, this answers `402` with `payment_required` and says which, until it is on the plan or deleted. See [One free workspace per person](/guides/usage-and-billing/#one-free-workspace-per-person)."
73+ },
74+ "get_workspace": {
75+ "params": {
76+ "workspace": "acme-labs"
77+ },
78+ "response": {
79+ "id": "wsp_01m43teqa9em6bje0bhvdj4jkb",
80+ "slug": "acme-labs",
81+ "name": "Acme Labs",
82+ "description": "Rockets, and the software that flies them.",
83+ "created_at": "2026-10-04T16:02:51.337Z",
84+ "member_count": 3,
85+ "base_permission": "write",
86+ "team_creation": "members"
87+ },
88+ "notes": "`team_creation` is who may create its teams: `members` (any member, the default) or `owners`. Change it, and the rest, with [`PATCH /workspaces/{workspace}`](/reference/api/workspaces/update-workspace/). `404` for anyone who is not a member. See [Workspaces](/guides/workspaces/)."
89+ },
90+ "update_workspace": {
91+ "params": {
92+ "workspace": "acme-labs"
93+ },
94+ "request": {
95+ "name": "Acme Labs",
96+ "description": "Rockets, and the software that flies them.",
97+ "team_creation": "owners"
98+ },
99+ "response": {
100+ "id": "wsp_01m43teqa9em6bje0bhvdj4jkb",
101+ "slug": "acme-labs",
102+ "name": "Acme Labs",
103+ "description": "Rockets, and the software that flies them.",
104+ "created_at": "2026-10-04T16:02:51.337Z",
105+ "member_count": 3,
106+ "base_permission": "write",
107+ "team_creation": "owners"
108+ },
109+ "notes": "Only the fields given change. `name` is the display name; the slug, the first part of the workspace's addresses, stays as it is. `base_permission` needs the `access:admin` scope as well as `workspace:admin`; [`set_base_permission`](/reference/api/access/set-base-permission/) sets it alone. `team_creation` is `members` (any member may create a team, the default) or `owners`; teams already made stay. Refused with `403` for anyone but an owner signed in as a person. Recorded in the [audit log](/guides/audit-log/). See [Workspaces](/guides/workspaces/)."
110+ },
111+ "delete_workspace": {
112+ "request": {
113+ "confirm": "acme-labs"
114+ },
115+ "response": true,
116+ "notes": "Refused with `402` while billing cannot settle it, with a message that says what to do, and with `403` for anyone but an owner signed in as a person, or for a protected workspace. Its repositories, projects and apps go with it; g1t's support can restore it for 30 days. See [Delete a workspace](/guides/workspaces/#delete-a-workspace)."
117+ },
118+ "list_emails": {
119+ "response": {
120+ "emails": [
121+ {
122+ "email": "ada@example.com",
123+ "verified": true,
124+ "primary": true,
125+ "backup": false,
126+ "created_at": "2026-09-01T10:00:00.000Z",
127+ "verified_at": "2026-09-01T10:02:11.000Z"
128+ },
129+ {
130+ "email": "ada@acme.com",
131+ "verified": true,
132+ "primary": false,
133+ "backup": true,
134+ "created_at": "2026-10-02T09:30:00.000Z",
135+ "verified_at": "2026-10-02T09:31:40.000Z"
136+ },
137+ {
138+ "email": "ada.l@example.org",
139+ "verified": false,
140+ "primary": false,
141+ "backup": false,
142+ "created_at": "2026-10-05T14:12:03.000Z",
143+ "verified_at": null
144+ }
145+ ],
146+ "private_email": true,
147+ "block_private_pushes": false,
148+ "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
149+ "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
150+ "limit": 10
151+ },
152+ "notes": "Your primary address comes first, then confirmed addresses, then unconfirmed ones. Any confirmed address signs you in, can reset your password and attributes commits to you. See [Email addresses](/guides/authentication/#email-addresses)."
153+ },
154+ "add_email": {
155+ "request": {
156+ "email": "ada.l@example.org",
157+ "password": "…"
158+ },
159+ "response": {
160+ "emails": [
161+ {
162+ "email": "ada@example.com",
163+ "verified": true,
164+ "primary": true,
165+ "backup": false,
166+ "created_at": "2026-09-01T10:00:00.000Z",
167+ "verified_at": "2026-09-01T10:02:11.000Z"
168+ },
169+ {
170+ "email": "ada@acme.com",
171+ "verified": true,
172+ "primary": false,
173+ "backup": true,
174+ "created_at": "2026-10-02T09:30:00.000Z",
175+ "verified_at": "2026-10-02T09:31:40.000Z"
176+ },
177+ {
178+ "email": "ada.l@example.org",
179+ "verified": false,
180+ "primary": false,
181+ "backup": false,
182+ "created_at": "2026-10-05T14:12:03.000Z",
183+ "verified_at": null
184+ }
185+ ],
186+ "private_email": true,
187+ "block_private_pushes": false,
188+ "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
189+ "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
190+ "limit": 10
191+ },
192+ "notes": "Answers `403` with code `reauth_required` when `password` is missing or wrong, and `409` when another account has confirmed the address. The new address stays unconfirmed until its link is followed."
193+ },
194+ "remove_email": {
195+ "request": {
196+ "password": "…"
197+ },
198+ "response": {
199+ "emails": [
200+ {
201+ "email": "ada@example.com",
202+ "verified": true,
203+ "primary": true,
204+ "backup": false,
205+ "created_at": "2026-09-01T10:00:00.000Z",
206+ "verified_at": "2026-09-01T10:02:11.000Z"
207+ },
208+ {
209+ "email": "ada@acme.com",
210+ "verified": true,
211+ "primary": false,
212+ "backup": true,
213+ "created_at": "2026-10-02T09:30:00.000Z",
214+ "verified_at": "2026-10-02T09:31:40.000Z"
215+ },
216+ {
217+ "email": "ada.l@example.org",
218+ "verified": false,
219+ "primary": false,
220+ "backup": false,
221+ "created_at": "2026-10-05T14:12:03.000Z",
222+ "verified_at": null
223+ }
224+ ],
225+ "private_email": true,
226+ "block_private_pushes": false,
227+ "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
228+ "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
229+ "limit": 10
230+ },
231+ "notes": "Give the address in the path, URL-encoded: `DELETE /user/emails/ada.l%40example.org`. Answers `409` for your primary address or your last confirmed one."
232+ },
233+ "update_email_settings": {
234+ "request": {
235+ "primary": "ada@acme.com",
236+ "password": "…"
237+ },
238+ "response": {
239+ "emails": [
240+ {
241+ "email": "ada@example.com",
242+ "verified": true,
243+ "primary": true,
244+ "backup": false,
245+ "created_at": "2026-09-01T10:00:00.000Z",
246+ "verified_at": "2026-09-01T10:02:11.000Z"
247+ },
248+ {
249+ "email": "ada@acme.com",
250+ "verified": true,
251+ "primary": false,
252+ "backup": true,
253+ "created_at": "2026-10-02T09:30:00.000Z",
254+ "verified_at": "2026-10-02T09:31:40.000Z"
255+ },
256+ {
257+ "email": "ada.l@example.org",
258+ "verified": false,
259+ "primary": false,
260+ "backup": false,
261+ "created_at": "2026-10-05T14:12:03.000Z",
262+ "verified_at": null
263+ }
264+ ],
265+ "private_email": true,
266+ "block_private_pushes": false,
267+ "noreply": "6c1d0efg+ada@users.noreply.g1t.sh",
268+ "commit_email": "6c1d0efg+ada@users.noreply.g1t.sh",
269+ "limit": 10
270+ },
271+ "notes": "Only the fields given change. `primary` and `backup` need `password`; `private_email` and `block_private_pushes` do not."
272+ },
273+ "list_invites": {
274+ "response": {
275+ "mode": "invite",
276+ "allowance": {
277+ "limit": 5,
278+ "used": 2,
279+ "remaining": 3
280+ },
281+ "workspaces": [
282+ {
283+ "slug": "acme-labs",
284+ "allowance": {
285+ "limit": 20,
286+ "used": 4,
287+ "remaining": 16
288+ }
289+ }
290+ ],
291+ "invites": [
292+ {
293+ "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
294+ "code": "g1t-k7m2-q9xd-4hpw-…",
295+ "hint": "g1t-k7m2",
296+ "email": "ada@example.com",
297+ "kind": "account",
298+ "workspace": null,
299+ "status": "pending",
300+ "charged_to": "user",
301+ "invited_by": "syntaqx",
302+ "redeemed_by": null,
303+ "created_at": "2026-10-05T17:00:00.000Z",
304+ "expires_at": "2026-11-04T17:00:00.000Z",
305+ "redeemed_at": null,
306+ "revoked_at": null
307+ },
308+ {
309+ "id": "inv_01kp1v3c4d5e6f7g8h9j0k1m2n",
310+ "code": null,
311+ "hint": "g1t-p3rt",
312+ "email": null,
313+ "kind": "account",
314+ "workspace": null,
315+ "status": "redeemed",
316+ "charged_to": "user",
317+ "invited_by": "syntaqx",
318+ "redeemed_by": "grace",
319+ "created_at": "2026-10-02T09:12:40.000Z",
320+ "expires_at": "2026-11-01T09:12:40.000Z",
321+ "redeemed_at": "2026-10-02T11:30:05.000Z",
322+ "revoked_at": null
323+ }
324+ ]
325+ },
326+ "notes": "`allowance.limit` and `allowance.remaining` are null when you have no limit. A revoked or expired invite that was never used is not counted. Ask for more at hey@flagon.io with the subject `[g1t Invites]`. See [Invites](/guides/authentication/#invites)."
327+ },
328+ "create_invite": {
329+ "request": {
330+ "email": "ada@example.com"
331+ },
332+ "response": {
333+ "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
334+ "code": "g1t-k7m2-q9xd-4hpw-…",
335+ "hint": "g1t-k7m2",
336+ "email": "ada@example.com",
337+ "kind": "account",
338+ "workspace": null,
339+ "status": "pending",
340+ "charged_to": "user",
341+ "invited_by": "syntaqx",
342+ "redeemed_by": null,
343+ "created_at": "2026-10-05T17:00:00.000Z",
344+ "expires_at": "2026-11-04T17:00:00.000Z",
345+ "redeemed_at": null,
346+ "revoked_at": null
347+ },
348+ "notes": "Refused with `402` (`limit`) when you have no invites left, with `409` when you already have a pending invite for that address or it already has a g1t account, and with `403` for an agent's or a workspace's token. The code is returned in full; send people the link `https://g1t.sh/invite/<code>`."
349+ },
350+ "revoke_invite": {
351+ "response": {
352+ "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
353+ "code": null,
354+ "hint": "g1t-k7m2",
355+ "email": "ada@example.com",
356+ "kind": "account",
357+ "workspace": null,
358+ "status": "revoked",
359+ "charged_to": "user",
360+ "invited_by": "syntaqx",
361+ "redeemed_by": null,
362+ "created_at": "2026-10-05T17:00:00.000Z",
363+ "expires_at": "2026-11-04T17:00:00.000Z",
364+ "redeemed_at": null,
365+ "revoked_at": "2026-10-06T08:00:00.000Z"
366+ }
367+ },
368+ "list_workspace_invites": {
369+ "response": [
370+ {
371+ "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
372+ "code": "g1t-k7m2-q9xd-4hpw-…",
373+ "hint": "g1t-k7m2",
374+ "email": "ada@example.com",
375+ "kind": "account",
376+ "workspace": "acme-labs",
377+ "status": "pending",
378+ "charged_to": "workspace",
379+ "invited_by": "syntaqx",
380+ "redeemed_by": null,
381+ "created_at": "2026-10-05T17:00:00.000Z",
382+ "expires_at": "2026-11-04T17:00:00.000Z",
383+ "redeemed_at": null,
384+ "revoked_at": null
385+ },
386+ {
387+ "id": "inv_01kp1z9y8x7w6v5t4s3r2q1p0n",
388+ "code": "g1t-k7m2-q9xd-4hpw-…",
389+ "hint": "g1t-w2vb",
390+ "email": "linus@example.com",
391+ "kind": "workspace",
392+ "workspace": "acme-labs",
393+ "status": "pending",
394+ "charged_to": "none",
395+ "invited_by": "syntaqx",
396+ "redeemed_by": null,
397+ "created_at": "2026-10-05T17:00:00.000Z",
398+ "expires_at": "2026-11-04T17:00:00.000Z",
399+ "redeemed_at": null,
400+ "revoked_at": null
401+ }
402+ ]
403+ },
404+ "invite_member": {
405+ "request": {
406+ "email": "ada@example.com"
407+ },
408+ "response": {
409+ "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
410+ "code": "g1t-k7m2-q9xd-4hpw-…",
411+ "hint": "g1t-k7m2",
412+ "email": "ada@example.com",
413+ "kind": "account",
414+ "workspace": "acme-labs",
415+ "status": "pending",
416+ "charged_to": "workspace",
417+ "invited_by": "syntaqx",
418+ "redeemed_by": null,
419+ "created_at": "2026-10-05T17:00:00.000Z",
420+ "expires_at": "2026-11-04T17:00:00.000Z",
421+ "redeemed_at": null,
422+ "revoked_at": null
423+ },
424+ "notes": "`kind` is `workspace` when the address already has a g1t account (`charged_to` is then `none`), and `account` when accepting makes one. Both answers look alike to the caller on purpose: the invite is emailed either way. A free workspace cannot invite anyone: `402` with `payment_required`, until it starts the g1t plan."
425+ },
426+ "revoke_workspace_invite": {
427+ "response": {
428+ "id": "inv_01kp2x7m8n9q0r1s2t3v4w5x6y",
429+ "code": null,
430+ "hint": "g1t-k7m2",
431+ "email": "ada@example.com",
432+ "kind": "account",
433+ "workspace": "acme-labs",
434+ "status": "revoked",
435+ "charged_to": "workspace",
436+ "invited_by": "syntaqx",
437+ "redeemed_by": null,
438+ "created_at": "2026-10-05T17:00:00.000Z",
439+ "expires_at": "2026-11-04T17:00:00.000Z",
440+ "redeemed_at": null,
441+ "revoked_at": "2026-10-06T08:00:00.000Z"
442+ }
443+ },
444+ "list_repos": {
445+ "query": {
446+ "q": "hello"
447+ },
448+ "response": [
449+ {
450+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
451+ "namespace": "flagon-io",
452+ "name": "hello",
453+ "description": "A tiny service that says hello.",
454+ "is_private": false,
455+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
456+ "default_branch": "main",
457+ "fork_of": null,
458+ "protected": true,
459+ "created_at": "2026-09-28T14:11:52.640Z",
460+ "website": "https://hello.g1t.page",
461+ "archived_at": null
462+ }
463+ ],
464+ "notes": "Returns at most 50 repositories, newest first. Forks made for pull requests are left out."
465+ },
466+ "create_repo": {
467+ "request": {
468+ "workspace": "flagon-io",
469+ "name": "hello-cli",
470+ "description": "Command-line client for hello.",
471+ "private": false
472+ },
473+ "response": {
474+ "id": "rep_01m43tk1jhehztx23drs87f5fc",
475+ "namespace": "flagon-io",
476+ "name": "hello-cli",
477+ "description": "Command-line client for hello.",
478+ "is_private": false,
479+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
480+ "default_branch": "main",
481+ "fork_of": null,
482+ "protected": false,
483+ "created_at": "2026-10-04T16:05:12.913Z",
484+ "website": "https://hello.g1t.page",
485+ "archived_at": null
486+ },
487+ "notes": "`owner_id` is the id of the person who created the repository. With `import_url`, `default_branch` is the default branch of the repository copied."
488+ },
489+ "get_repo": {
490+ "response": {
491+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
492+ "namespace": "flagon-io",
493+ "name": "hello",
494+ "description": "A tiny service that says hello.",
495+ "is_private": false,
496+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
497+ "default_branch": "main",
498+ "fork_of": null,
499+ "protected": true,
500+ "created_at": "2026-09-28T14:11:52.640Z",
501+ "website": "https://hello.g1t.page",
502+ "archived_at": null
503+ }
504+ },
505+ "update_repo": {
506+ "request": {
507+ "description": "Says hello, politely.",
508+ "website": "hello.g1t.page",
509+ "default_branch": "trunk",
510+ "protected": true
511+ },
512+ "response": {
513+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
514+ "namespace": "flagon-io",
515+ "name": "hello",
516+ "description": "Says hello, politely.",
517+ "is_private": false,
518+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
519+ "default_branch": "trunk",
520+ "fork_of": null,
521+ "protected": true,
522+ "created_at": "2026-09-28T14:11:52.640Z",
523+ "topics": [
524+ "http",
525+ "example"
526+ ],
527+ "website": "https://hello.g1t.page",
528+ "archived_at": null
529+ },
530+ "notes": "Only the fields given change. `website` gets `https://` when no scheme is given; an empty string clears it. `default_branch` must name a branch that exists (`422` otherwise); it is changed after the other fields. `description`, `website`, `topics` and `protected` need the Maintain role or higher, and `private` and `default_branch` the Admin role (`403` otherwise, saying which role). Changing `private` here needs no confirmation; `POST /repos/{owner}/{name}/visibility` asks for one. Making it private is refused with `402` when a free workspace's private storage has no room for it. See [Managing a repository](/guides/managing-repositories/) and [Access and roles](/guides/access-and-roles/)."
531+ },
532+ "transfer_repo": {
533+ "request": {
534+ "to": "flagon-io"
535+ },
536+ "response": {
537+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
538+ "namespace": "flagon-io",
539+ "name": "hello",
540+ "description": "A tiny service that says hello.",
541+ "is_private": false,
542+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
543+ "default_branch": "main",
544+ "fork_of": null,
545+ "protected": true,
546+ "created_at": "2026-09-28T14:11:52.640Z",
547+ "website": "https://hello.g1t.page",
548+ "archived_at": null
549+ },
550+ "notes": "The repository at its new address. Refused with `409` when the destination already has a repository of that name, `403` unless you own both workspaces, and `402` when a free destination has no room for a private repository. The old address redirects. See [Transferring a repository](/guides/transferring-repositories/)."
551+ },
552+ "rename_repo": {
553+ "request": {
554+ "name": "greeter"
555+ },
556+ "response": {
557+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
558+ "namespace": "flagon-io",
559+ "name": "greeter",
560+ "description": "A tiny service that says hello.",
561+ "is_private": false,
562+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
563+ "default_branch": "main",
564+ "fork_of": null,
565+ "protected": true,
566+ "created_at": "2026-09-28T14:11:52.640Z",
567+ "topics": [
568+ "http",
569+ "example"
570+ ],
571+ "website": "https://hello.g1t.page",
572+ "archived_at": null
573+ },
574+ "notes": "The repository under its new name. Needs the Admin role (`403` otherwise). Refused with `409` when the workspace already has a repository of that name, a recently deleted one included, and with `422` when the name is not valid. The old address redirects. See [Rename a repository](/guides/managing-repositories/#rename-a-repository)."
575+ },
576+ "rename_branch": {
577+ "params": {
578+ "owner": "flagon-io",
579+ "name": "hello",
580+ "branch": "feature/login"
581+ },
582+ "request": {
583+ "new_name": "feature/sign-in"
584+ },
585+ "response": {
586+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
587+ "namespace": "flagon-io",
588+ "name": "hello",
589+ "description": "A tiny service that says hello.",
590+ "is_private": false,
591+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
592+ "default_branch": "main",
593+ "fork_of": null,
594+ "protected": true,
595+ "created_at": "2026-09-28T14:11:52.640Z",
596+ "topics": [
597+ "http",
598+ "example"
599+ ],
600+ "website": "https://hello.g1t.page",
601+ "archived_at": null
602+ },
603+ "notes": "The repository after the rename; renaming the default branch changes `default_branch`. Send a branch name with slashes URL-encoded, as one path segment. Refused with `404` when there is no such branch, `409` when a branch named `new_name` exists, `422` when `new_name` is not a valid branch name, and `403` without the Write role, or without the Admin role for the default branch. See [Rename a branch](/guides/managing-repositories/#rename-a-branch)."
604+ },
605+ "set_repo_visibility": {
606+ "request": {
607+ "private": true,
608+ "confirm": "flagon-io/hello"
609+ },
610+ "response": {
611+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
612+ "namespace": "flagon-io",
613+ "name": "hello",
614+ "description": "A tiny service that says hello.",
615+ "is_private": true,
616+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
617+ "default_branch": "main",
618+ "fork_of": null,
619+ "protected": true,
620+ "created_at": "2026-09-28T14:11:52.640Z",
621+ "topics": [
622+ "http",
623+ "example"
624+ ],
625+ "website": "https://hello.g1t.page",
626+ "archived_at": null
627+ },
628+ "notes": "Needs the Admin role (`403` otherwise). Refused with `422` when `confirm` is not the repository's full name, and with `402` when a free workspace's private storage has no room for it. See [Change who can see a repository](/guides/managing-repositories/#change-who-can-see-a-repository)."
629+ },
630+ "archive_repo": {
631+ "response": {
632+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
633+ "namespace": "flagon-io",
634+ "name": "hello",
635+ "description": "A tiny service that says hello.",
636+ "is_private": false,
637+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
638+ "default_branch": "main",
639+ "fork_of": null,
640+ "protected": true,
641+ "created_at": "2026-09-28T14:11:52.640Z",
642+ "topics": [
643+ "http",
644+ "example"
645+ ],
646+ "website": "https://hello.g1t.page",
647+ "archived_at": "2026-10-05T09:30:00.000Z"
648+ },
649+ "notes": "The repository, with `archived_at` set. Needs the Admin role (`403` otherwise). See [Archive a repository](/guides/managing-repositories/#archive-a-repository)."
650+ },
651+ "unarchive_repo": {
652+ "response": {
653+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
654+ "namespace": "flagon-io",
655+ "name": "hello",
656+ "description": "A tiny service that says hello.",
657+ "is_private": false,
658+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
659+ "default_branch": "main",
660+ "fork_of": null,
661+ "protected": true,
662+ "created_at": "2026-09-28T14:11:52.640Z",
663+ "topics": [
664+ "http",
665+ "example"
666+ ],
667+ "website": "https://hello.g1t.page",
668+ "archived_at": null
669+ },
670+ "notes": "The repository, with `archived_at` null. Needs the Admin role (`403` otherwise)."
671+ },
672+ "delete_repo": {
673+ "request": {
674+ "confirm": "flagon-io/hello"
675+ },
676+ "response": {
677+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
678+ "namespace": "flagon-io",
679+ "name": "hello",
680+ "description": "A tiny service that says hello.",
681+ "is_private": false,
682+ "deleted_at": "2026-10-05T09:30:00.000Z",
683+ "deleted_by": "syntaqx",
684+ "purge_after": "2026-11-04T09:30:00.000Z"
685+ },
686+ "notes": "The deleted repository and when it will be purged, 30 days on. Owners of the workspace only (`403`), whatever their role on the repository. Refused with `422` when `confirm` is not its full name. Its name stays taken until it is purged. See [Delete a repository](/guides/managing-repositories/#delete-a-repository)."
687+ },
688+ "list_deleted_repos": {
689+ "params": {
690+ "workspace": "flagon-io"
691+ },
692+ "response": [
693+ {
694+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
695+ "namespace": "flagon-io",
696+ "name": "hello",
697+ "description": "A tiny service that says hello.",
698+ "is_private": false,
699+ "deleted_at": "2026-10-05T09:30:00.000Z",
700+ "deleted_by": "syntaqx",
701+ "purge_after": "2026-11-04T09:30:00.000Z"
702+ }
703+ ],
704+ "notes": "Newest first. Empty for anyone who is not an owner of the workspace."
705+ },
706+ "restore_repo": {
707+ "response": {
708+ "id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
709+ "namespace": "flagon-io",
710+ "name": "hello",
711+ "description": "A tiny service that says hello.",
712+ "is_private": false,
713+ "owner_id": "usr_01kkntcg1eeb98j62xjm7eh09p",
714+ "default_branch": "main",
715+ "fork_of": null,
716+ "protected": true,
717+ "created_at": "2026-09-28T14:11:52.640Z",
718+ "topics": [
719+ "http",
720+ "example"
721+ ],
722+ "website": "https://hello.g1t.page",
723+ "archived_at": null
724+ },
725+ "notes": "The repository, back at its address. Name it by the path it had. Owners only (`403`); `404` when no deleted repository had that path, or it has been purged. See [Restore a repository](/guides/managing-repositories/#restore-a-repository)."
726+ },
727+ "purge_repo": {
728+ "request": {
729+ "confirm": "flagon-io/hello"
730+ },
731+ "response": true,
732+ "notes": "Permanent: it cannot be restored afterwards, and its name is free again. Only a deleted repository can be purged (`404` otherwise). Owners only (`403`); `422` when `confirm` is not its full name."
733+ },
734+ "get_repo_settings": {
735+ "response": {
736+ "auto_merge": false,
737+ "required_checks": [
738+ "CI"
739+ ],
740+ "require_up_to_date": false,
741+ "required_approvals": 0,
742+ "count_agent_approvals": true,
743+ "allow_ignoring_checks": true,
744+ "agent_review": true,
745+ "max_revisions": 2,
746+ "merge_queue": false,
747+ "hold_low_confidence": true,
748+ "require_code_owner_review": false,
749+ "updated_by": null,
750+ "updated_at": null
751+ }
752+ },
753+ "update_repo_settings": {
754+ "request": {
755+ "required_checks": [
756+ "CI",
757+ "g1t / deploy"
758+ ],
759+ "required_approvals": 1,
760+ "count_agent_approvals": false,
761+ "merge_queue": true,
762+ "require_code_owner_review": true
763+ },
764+ "response": {
765+ "auto_merge": false,
766+ "required_checks": [
767+ "CI",
768+ "g1t / deploy"
769+ ],
770+ "require_up_to_date": false,
771+ "required_approvals": 1,
772+ "count_agent_approvals": false,
773+ "allow_ignoring_checks": true,
774+ "agent_review": true,
775+ "max_revisions": 2,
776+ "merge_queue": true,
777+ "hold_low_confidence": true,
778+ "require_code_owner_review": true,
779+ "updated_by": "syntaqx",
780+ "updated_at": "2026-10-04T16:20:37.508Z"
781+ },
782+ "notes": "`required_checks` replaces the whole list: at most 20 names, each a workflow's name or another status's context, as [`list_check_names`](/reference/api/repositories/list-check-names/) gives them. A pull request merges only once each passes on its head; one nothing has reported holds it too. With the merge queue on, each must also pass on the queued state, so the workflows behind them need `merge_group` in their `on:`. `required_approvals` is at most 6 and `max_revisions` at most 5. See [what a repository can ask for](/guides/working-with-g1t/#what-a-repository-can-ask-for). `hold_low_confidence` is on unless turned off: see [confidence](/guides/working-with-g1t/#how-sure-the-agent-is). With `require_code_owner_review`, a pull request into the default branch merges only once the code owners of every file it changes have approved it, as many as each section of its CODEOWNERS file asks: see [Code owners](/guides/codeowners/)."
783+ },
784+ "list_check_names": {
785+ "response": [
786+ {
787+ "name": "CI",
788+ "events": [
789+ "pull_request",
790+ "merge_group",
791+ "push"
792+ ],
793+ "last_seen": "2026-10-06T09:14:02.118Z"
794+ },
795+ {
796+ "name": "g1t / deploy",
797+ "events": [],
798+ "last_seen": "2026-10-06T08:51:40.006Z"
799+ }
800+ ],
801+ "notes": "The names reported on the repository's commits in the last 30 days, most recent first. A workflow reports a check named after it (`CI`), for each event it ran for; another tool, such as a deployment, reports its own name (`g1t / deploy`). Empty until something has reported on a commit: add a workflow in `.g1t/workflows` first."
802+ },
803+ "get_codeowners_errors": {
804+ "params": {
805+ "owner": "flagon-io",
806+ "name": "hello"
807+ },
808+ "query": {
809+ "ref": "main"
810+ },
811+ "response": {
812+ "path": ".github/CODEOWNERS",
813+ "ref": "main",
814+ "size": 412,
815+ "rules": 9,
816+ "sections": [
817+ "Docs"
818+ ],
819+ "errors": [
820+ {
821+ "line": 4,
822+ "kind": "unknown_team",
823+ "token": "@flagon-io/platform",
824+ "message": "@flagon-io/platform is not a team of flagon-io."
825+ },
826+ {
827+ "line": 7,
828+ "kind": "negation",
829+ "token": "!docs/internal/",
830+ "message": "!docs/internal/ starts with !, and negation is not supported; this line is skipped. Give the path a later rule with no owners instead."
831+ }
832+ ]
833+ },
834+ "notes": "The file is the first of `.g1t/CODEOWNERS`, `.github/CODEOWNERS`, `CODEOWNERS`, `docs/CODEOWNERS` and `.gitlab/CODEOWNERS` found on `ref` (the default branch when left out); `path` is null when there is none, with no errors. Each error has its `line` (0 for the file as a whole), the `token` at fault, a `message`, and a `kind`:\n\n| `kind` | |\n| --- | --- |\n| `too_large` | The file is over 3 MB and was ignored. |\n| `negation` | A pattern starting with `!`; the line was skipped. |\n| `character_range` | A pattern with `[` or `]`; the line was skipped. |\n| `bad_pattern` | A pattern that names no path; the line was skipped. |\n| `bad_owner` | An owner that is not `@user`, `@workspace/team` or an email address. |\n| `bad_section` | A section header that could not be read. |\n| `unknown_user` | No account has that username. |\n| `unknown_team` | The workspace has no team of that slug. |\n| `unknown_email` | No account has confirmed that address. |\n| `no_write_access` | The person cannot write to the repository. |\n| `team_no_access` | The team has no write access to the repository. |\n\nSee [Code owners](/guides/codeowners/)."
835+ },
836+ "list_events": {
837+ "query": {
838+ "before": "evt_01m43t2a6c9e3g7j1m5q9t3x7b"
839+ },
840+ "response": [
841+ {
842+ "id": "evt_01m43smh3ve52vkcna207vqctf",
843+ "type": "pull.opened",
844+ "source": "work",
845+ "time": "2026-10-01T18:20:02.117Z",
846+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
847+ "actor": "usr_01kkntcg1eeb98j62xjm7eh09p",
848+ "data": {
849+ "pull_id": "pr_01m43smh3vexsr5pmp60qwv0vs",
850+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
851+ "number": 14,
852+ "issue": 12,
853+ "agent": "claude-code"
854+ }
855+ },
856+ {
857+ "id": "evt_01m43shrzpf2vt5rxbb02z0xjt",
858+ "type": "issue.opened",
859+ "source": "work",
860+ "time": "2026-10-01T18:04:11.482Z",
861+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
862+ "actor": "usr_01kkntcg1eeb98j62xjm7eh09p",
863+ "data": {
864+ "issue_id": "iss_01m43shrzpfe49x74ga7sj1c6v",
865+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
866+ "number": 12,
867+ "title": "Greeting should name the caller"
868+ }
869+ }
870+ ],
871+ "notes": "Returns 50 events a page. To page back, send the `id` of the last event you have as `before`. `actor` is a user id, and `data` depends on `type`."
872+ },
873+ "list_issues": {
874+ "query": {
875+ "state": "open",
876+ "label": "feature"
877+ },
878+ "response": [
879+ {
880+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
881+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
882+ "number": 12,
883+ "title": "Greeting should name the caller",
884+ "body": "Take a name from the first argument; fall back to world.",
885+ "labels": [
886+ "feature"
887+ ],
888+ "state": "open",
889+ "reason": null,
890+ "resolved_by": null,
891+ "author": {
892+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
893+ "username": "syntaqx",
894+ "kind": "user",
895+ "verified": false,
896+ "workspaces": []
897+ },
898+ "requested_by": null,
899+ "created_at": "2026-10-01T18:04:11.482Z",
900+ "updated_at": "2026-10-01T18:04:11.482Z",
901+ "closed_at": null,
902+ "pull_count": 1,
903+ "comment_count": 0,
904+ "assignees": [],
905+ "blocked_by": [],
906+ "queued": false,
907+ "agent": "claude-code",
908+ "milestone": null
909+ }
910+ ],
911+ "notes": "Returns at most 100 issues, newest first. `comment_count` counts comments, not events such as \"opened #14 for this\"."
912+ },
913+ "create_issue": {
914+ "request": {
915+ "title": "Greeting should name the caller",
916+ "body": "Take a name from the first argument; fall back to world.",
917+ "labels": [
918+ "feature"
919+ ]
920+ },
921+ "response": {
922+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
923+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
924+ "number": 12,
925+ "title": "Greeting should name the caller",
926+ "body": "Take a name from the first argument; fall back to world.",
927+ "labels": [
928+ "feature"
929+ ],
930+ "state": "open",
931+ "reason": null,
932+ "resolved_by": null,
933+ "author": {
934+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
935+ "username": "syntaqx",
936+ "kind": "user",
937+ "verified": false,
938+ "workspaces": []
939+ },
940+ "requested_by": null,
941+ "created_at": "2026-10-01T18:04:11.482Z",
942+ "updated_at": "2026-10-01T18:04:11.482Z",
943+ "closed_at": null,
944+ "pull_count": 0,
945+ "comment_count": 0,
946+ "assignees": [],
947+ "blocked_by": [],
948+ "queued": false,
949+ "agent": null,
950+ "milestone": null
951+ },
952+ "notes": "Labels are lowercased. A label not used before is created."
953+ },
954+ "get_issue": {
955+ "response": {
956+ "issue": {
957+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
958+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
959+ "number": 12,
960+ "title": "Greeting should name the caller",
961+ "body": "Take a name from the first argument; fall back to world.",
962+ "labels": [
963+ "feature"
964+ ],
965+ "state": "closed",
966+ "reason": "completed",
967+ "resolved_by": 14,
968+ "author": {
969+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
970+ "username": "syntaqx",
971+ "kind": "user",
972+ "verified": false,
973+ "workspaces": []
974+ },
975+ "requested_by": null,
976+ "created_at": "2026-10-01T18:04:11.482Z",
977+ "updated_at": "2026-10-01T18:52:17.093Z",
978+ "closed_at": "2026-10-01T18:52:17.093Z",
979+ "pull_count": 2,
980+ "comment_count": 0,
981+ "assignees": [],
982+ "blocked_by": [],
983+ "queued": false,
984+ "agent": null,
985+ "milestone": null
986+ },
987+ "pulls": [
988+ {
989+ "id": "pr_01m43sjq8tcz5rbm2a7k4d9e6w",
990+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
991+ "number": 13,
992+ "issue": 12,
993+ "title": "Greeting should name the caller",
994+ "body": null,
995+ "agent": "claude-code",
996+ "runtime": "external",
997+ "status": "closed",
998+ "fork": {
999+ "namespace": "pulls",
1000+ "name": "pr_01m43sjq8tcz5rbm2a7k4d9e6w"
1001+ },
1002+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1003+ "branch": null,
1004+ "head_commit": null,
1005+ "merge_base": null,
1006+ "merged_by": null,
1007+ "merged_at": null,
1008+ "superseded_by": 14,
1009+ "check_status": null,
1010+ "files": [],
1011+ "assignees": [],
1012+ "reviewers": [],
1013+ "labels": [],
1014+ "milestone": null,
1015+ "base": "main",
1016+ "author": {
1017+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1018+ "username": "syntaqx",
1019+ "kind": "user",
1020+ "verified": false,
1021+ "workspaces": []
1022+ },
1023+ "requested_by": null,
1024+ "created_at": "2026-10-01T18:20:02.117Z",
1025+ "updated_at": "2026-10-01T18:20:02.117Z"
1026+ },
1027+ {
1028+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1029+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1030+ "number": 14,
1031+ "issue": 12,
1032+ "title": "Greeting should name the caller",
1033+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1034+ "agent": "claude-code",
1035+ "runtime": "external",
1036+ "status": "merged",
1037+ "fork": {
1038+ "namespace": "pulls",
1039+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1040+ },
1041+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1042+ "branch": null,
1043+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1044+ "merge_base": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
1045+ "merged_by": "syntaqx",
1046+ "merged_at": "2026-10-01T18:52:17.093Z",
1047+ "superseded_by": null,
1048+ "check_status": "passed",
1049+ "files": [
1050+ {
1051+ "path": "src/main.rs",
1052+ "additions": 6,
1053+ "deletions": 2
1054+ }
1055+ ],
1056+ "assignees": [],
1057+ "reviewers": [
1058+ "ana"
1059+ ],
1060+ "labels": [],
1061+ "milestone": null,
1062+ "base": "main",
1063+ "author": {
1064+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1065+ "username": "syntaqx",
1066+ "kind": "user",
1067+ "verified": false,
1068+ "workspaces": []
1069+ },
1070+ "requested_by": null,
1071+ "created_at": "2026-10-01T18:20:02.117Z",
1072+ "updated_at": "2026-10-01T18:52:17.093Z"
1073+ }
1074+ ],
1075+ "comments": [
1076+ {
1077+ "id": "cmt_01m43sr2b7d5f0j6k3n8p1q4v9",
1078+ "kind": "event",
1079+ "author": {
1080+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1081+ "username": "syntaqx",
1082+ "kind": "user",
1083+ "verified": false,
1084+ "workspaces": []
1085+ },
1086+ "body": "opened #14 for this",
1087+ "path": null,
1088+ "line": null,
1089+ "verdict": null,
1090+ "created_at": "2026-10-01T18:20:02.141Z"
1091+ }
1092+ ]
1093+ },
1094+ "notes": "A closed issue says how it was closed: `reason` is `completed` or `not_planned`, and `resolved_by` is the number of the pull request whose merge closed it. Each pull request made for it is listed; one closed because another was merged has `superseded_by` set."
1095+ },
1096+ "update_issue": {
1097+ "request": {
1098+ "labels": [
1099+ "feature",
1100+ "good first issue"
1101+ ],
1102+ "assignees": [
1103+ "syntaqx"
1104+ ],
1105+ "milestone": 3
1106+ },
1107+ "response": {
1108+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1109+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1110+ "number": 12,
1111+ "title": "Greeting should name the caller",
1112+ "body": "Take a name from the first argument; fall back to world.",
1113+ "labels": [
1114+ "feature",
1115+ "good first issue"
1116+ ],
1117+ "state": "open",
1118+ "reason": null,
1119+ "resolved_by": null,
1120+ "author": {
1121+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1122+ "username": "syntaqx",
1123+ "kind": "user",
1124+ "verified": false,
1125+ "workspaces": []
1126+ },
1127+ "requested_by": null,
1128+ "created_at": "2026-10-01T18:04:11.482Z",
1129+ "updated_at": "2026-10-01T18:09:47.305Z",
1130+ "closed_at": null,
1131+ "pull_count": 0,
1132+ "comment_count": 0,
1133+ "assignees": [
1134+ "syntaqx"
1135+ ],
1136+ "blocked_by": [],
1137+ "queued": false,
1138+ "agent": null,
1139+ "milestone": {
1140+ "number": 3,
1141+ "title": "Launch"
1142+ }
1143+ }
1144+ },
1145+ "close_issue": {
1146+ "request": {
1147+ "reason": "not_planned"
1148+ },
1149+ "response": {
1150+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1151+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1152+ "number": 12,
1153+ "title": "Greeting should name the caller",
1154+ "body": "Take a name from the first argument; fall back to world.",
1155+ "labels": [
1156+ "feature"
1157+ ],
1158+ "state": "closed",
1159+ "reason": "not_planned",
1160+ "resolved_by": null,
1161+ "author": {
1162+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1163+ "username": "syntaqx",
1164+ "kind": "user",
1165+ "verified": false,
1166+ "workspaces": []
1167+ },
1168+ "requested_by": null,
1169+ "created_at": "2026-10-01T18:04:11.482Z",
1170+ "updated_at": "2026-10-01T19:30:00.214Z",
1171+ "closed_at": "2026-10-01T19:30:00.214Z",
1172+ "pull_count": 0,
1173+ "comment_count": 0,
1174+ "assignees": [],
1175+ "blocked_by": [],
1176+ "queued": false,
1177+ "agent": null,
1178+ "milestone": null
1179+ }
1180+ },
1181+ "reopen_issue": {
1182+ "response": {
1183+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1184+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1185+ "number": 12,
1186+ "title": "Greeting should name the caller",
1187+ "body": "Take a name from the first argument; fall back to world.",
1188+ "labels": [
1189+ "feature"
1190+ ],
1191+ "state": "open",
1192+ "reason": null,
1193+ "resolved_by": null,
1194+ "author": {
1195+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1196+ "username": "syntaqx",
1197+ "kind": "user",
1198+ "verified": false,
1199+ "workspaces": []
1200+ },
1201+ "requested_by": null,
1202+ "created_at": "2026-10-01T18:04:11.482Z",
1203+ "updated_at": "2026-10-01T19:41:52.830Z",
1204+ "closed_at": null,
1205+ "pull_count": 0,
1206+ "comment_count": 0,
1207+ "assignees": [],
1208+ "blocked_by": [],
1209+ "queued": false,
1210+ "agent": null,
1211+ "milestone": null
1212+ }
1213+ },
1214+ "assign_issue": {
1215+ "request": {
1216+ "instructions": "Keep the change to src/main.rs."
1217+ },
1218+ "response": {
1219+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1220+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1221+ "number": 14,
1222+ "issue": 12,
1223+ "title": "Greeting should name the caller",
1224+ "body": null,
1225+ "agent": "g1t",
1226+ "runtime": "hosted",
1227+ "status": "draft",
1228+ "fork": {
1229+ "namespace": "pulls",
1230+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1231+ },
1232+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1233+ "branch": null,
1234+ "head_commit": null,
1235+ "merge_base": null,
1236+ "merged_by": null,
1237+ "merged_at": null,
1238+ "superseded_by": null,
1239+ "check_status": null,
1240+ "files": [],
1241+ "assignees": [],
1242+ "reviewers": [],
1243+ "labels": [],
1244+ "milestone": null,
1245+ "base": "main",
1246+ "author": {
1247+ "id": "usr_g1t_agent",
1248+ "username": "g1t",
1249+ "kind": "agent",
1250+ "verified": false,
1251+ "workspaces": []
1252+ },
1253+ "requested_by": {
1254+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1255+ "username": "syntaqx",
1256+ "kind": "user",
1257+ "verified": false,
1258+ "workspaces": []
1259+ },
1260+ "created_at": "2026-10-01T18:20:02.117Z",
1261+ "updated_at": "2026-10-01T18:20:02.117Z",
1262+ "confidence": null
1263+ },
1264+ "notes": "The response is the pull request g1t opened, still a draft. g1t is its `author` and you are its `requested_by`: you may manage it as if you had opened it, and cannot approve it yourself. Follow it with [get a pull request](/reference/api/pull-requests/get-pull-request/): `lifecycle` says what the agent is doing."
1265+ },
1266+ "delegate": {
1267+ "request": {
1268+ "title": "Retry webhooks with exponential backoff",
1269+ "body": "Deliveries that fail are dropped today. Retry them with exponential backoff, up to six times, then mark the delivery failed.\n\n## Definition of done\n\n- A delivery that fails is retried after 1, 2, 4, 8, 16 and 32 seconds.\n- After the sixth failure it is marked failed and shows on the webhook's page."
1270+ },
1271+ "response": {
1272+ "issue": {
1273+ "id": "iss_01m4a2c8v1t7k3q9x5n0r2w6yd",
1274+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1275+ "number": 41,
1276+ "title": "Retry webhooks with exponential backoff",
1277+ "body": "Deliveries that fail are dropped today. Retry them with exponential backoff, up to six times, then mark the delivery failed.",
1278+ "labels": [],
1279+ "state": "open",
1280+ "reason": null,
1281+ "resolved_by": null,
1282+ "author": {
1283+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1284+ "username": "syntaqx",
1285+ "kind": "user",
1286+ "verified": false,
1287+ "workspaces": []
1288+ },
1289+ "requested_by": null,
1290+ "created_at": "2026-10-05T14:02:11.204Z",
1291+ "updated_at": "2026-10-05T14:02:11.204Z",
1292+ "closed_at": null,
1293+ "pull_count": 1,
1294+ "comment_count": 0,
1295+ "assignees": [],
1296+ "blocked_by": [],
1297+ "queued": false,
1298+ "agent": "g1t",
1299+ "milestone": null
1300+ },
1301+ "pull": {
1302+ "id": "pr_01m4a2c9b6e0h4m8q2t6x0a4d8",
1303+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1304+ "number": 42,
1305+ "issue": 41,
1306+ "title": "Retry webhooks with exponential backoff",
1307+ "body": null,
1308+ "agent": "g1t",
1309+ "runtime": "hosted",
1310+ "status": "draft",
1311+ "fork": {
1312+ "namespace": "pulls",
1313+ "name": "pr_01m4a2c9b6e0h4m8q2t6x0a4d8"
1314+ },
1315+ "fork_repo_id": "rep_01m4a2c9d2g6k0n4r8v2z6c0f4",
1316+ "branch": null,
1317+ "head_commit": null,
1318+ "merge_base": null,
1319+ "merged_by": null,
1320+ "merged_at": null,
1321+ "superseded_by": null,
1322+ "check_status": null,
1323+ "files": [],
1324+ "assignees": [],
1325+ "reviewers": [],
1326+ "labels": [],
1327+ "milestone": null,
1328+ "base": "main",
1329+ "author": {
1330+ "id": "usr_g1t_agent",
1331+ "username": "g1t",
1332+ "kind": "agent",
1333+ "verified": false,
1334+ "workspaces": []
1335+ },
1336+ "requested_by": {
1337+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1338+ "username": "syntaqx",
1339+ "kind": "user",
1340+ "verified": false,
1341+ "workspaces": []
1342+ },
1343+ "created_at": "2026-10-05T14:02:12.880Z",
1344+ "updated_at": "2026-10-05T14:02:12.880Z",
1345+ "confidence": null
1346+ },
1347+ "agent": {
1348+ "status": "started",
1349+ "code": null,
1350+ "message": null,
1351+ "fix_url": null
1352+ }
1353+ },
1354+ "notes": "The issue is opened whatever becomes of the agent. When the workspace's plan does not let it start, `pull` is null and `agent` says why and where to fix it, for example `{ \"status\": \"not_started\", \"code\": \"not_paid\", \"message\": \"Agents need a paid workspace. Start the $20 plan or try it with $5 of free usage after a card check: /acme/-/billing\", \"fix_url\": \"https://g1t.sh/acme/-/billing\" }`. With every agent slot busy, `status` is `queued` and it starts by itself when one frees up. See [putting an agent on something](/guides/working-with-g1t/#put-an-agent-on-it-in-one-step)."
1355+ },
1356+ "add_comment": {
1357+ "request": {
1358+ "body": "Should an empty name fall back to \"world\"?"
1359+ },
1360+ "response": {
1361+ "id": "cmt_01m43sv4c8e2g6j0m4q8t2x6a1",
1362+ "kind": "comment",
1363+ "author": {
1364+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1365+ "username": "syntaqx",
1366+ "kind": "user",
1367+ "verified": true,
1368+ "workspaces": [
1369+ {
1370+ "slug": "flagon-io",
1371+ "role": "owner"
1372+ }
1373+ ]
1374+ },
1375+ "body": "Should an empty name fall back to \"world\"?",
1376+ "path": null,
1377+ "line": null,
1378+ "verdict": null,
1379+ "created_at": "2026-10-01T18:12:30.551Z"
1380+ }
1381+ },
1382+ "list_labels": {
1383+ "response": [
1384+ {
1385+ "name": "bug",
1386+ "color": "d73a4a",
1387+ "description": "Something isn't working",
1388+ "issues": 4,
1389+ "pulls": 1
1390+ },
1391+ {
1392+ "name": "dependencies",
1393+ "color": "0366d6",
1394+ "description": "Updates a dependency",
1395+ "issues": 0,
1396+ "pulls": 6
1397+ },
1398+ {
1399+ "name": "good first issue",
1400+ "color": "7057ff",
1401+ "description": "Good for newcomers",
1402+ "issues": 2,
1403+ "pulls": 0
1404+ }
1405+ ],
1406+ "notes": "By name. A new repository starts with the default labels; add_default_labels adds those an older one is missing."
1407+ },
1408+ "plan_work": {
1409+ "request": {
1410+ "brief": "Greet people by name, from the command line and the web page."
1411+ },
1412+ "response": {
1413+ "plan_id": "pln_01m43s9c4e8g2j6m0q4t8x2b6d"
1414+ }
1415+ },
1416+ "get_plan": {
1417+ "params": {
1418+ "plan": "pln_01m43s9c4e8g2j6m0q4t8x2b6d"
1419+ },
1420+ "response": {
1421+ "id": "pln_01m43s9c4e8g2j6m0q4t8x2b6d",
1422+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1423+ "brief": "Greet people by name, from the command line and the web page.",
1424+ "status": "ready",
1425+ "summary": "Name parsing first, then the two places that print the greeting.",
1426+ "issues": [
1427+ {
1428+ "title": "Greeting should name the caller",
1429+ "body": "Accept an optional name in `greet()` and use it.",
1430+ "labels": [
1431+ "feature"
1432+ ],
1433+ "done": [
1434+ "`greet` prints \"Hello, ana!\" when given \"ana\", and \"Hello, world!\" with no argument."
1435+ ],
1436+ "files": [
1437+ "src/greet.rs"
1438+ ],
1439+ "depends_on": [],
1440+ "number": null
1441+ },
1442+ {
1443+ "title": "Show the caller's name on the web page",
1444+ "body": "Read `?name=` and pass it to `greet()`.",
1445+ "labels": [
1446+ "feature"
1447+ ],
1448+ "done": [
1449+ "The page at / shows the name given in ?name=, escaped."
1450+ ],
1451+ "files": [
1452+ "src/web.rs"
1453+ ],
1454+ "depends_on": [
1455+ 1
1456+ ],
1457+ "number": null
1458+ }
1459+ ],
1460+ "error": null,
1461+ "author": {
1462+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1463+ "username": "syntaqx",
1464+ "kind": "user",
1465+ "verified": false,
1466+ "workspaces": []
1467+ },
1468+ "created_at": "2026-10-01T17:58:40.006Z",
1469+ "finished_at": "2026-10-01T18:01:12.774Z",
1470+ "progress": [],
1471+ "exchanges": []
1472+ },
1473+ "notes": "A plan still `planning` after 20 minutes is reported as `failed`. `progress` follows each issue once the plan is applied."
1474+ },
1475+ "apply_plan": {
1476+ "params": {
1477+ "plan": "pln_01m43s9c4e8g2j6m0q4t8x2b6d"
1478+ },
1479+ "request": {
1480+ "assign": true
1481+ },
1482+ "response": {
1483+ "id": "pln_01m43s9c4e8g2j6m0q4t8x2b6d",
1484+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1485+ "brief": "Greet people by name, from the command line and the web page.",
1486+ "status": "applied",
1487+ "summary": "Name parsing first, then the two places that print the greeting.",
1488+ "issues": [
1489+ {
1490+ "title": "Greeting should name the caller",
1491+ "body": "Accept an optional name in `greet()` and use it.",
1492+ "labels": [
1493+ "feature"
1494+ ],
1495+ "done": [
1496+ "`greet` prints \"Hello, ana!\" when given \"ana\", and \"Hello, world!\" with no argument."
1497+ ],
1498+ "files": [
1499+ "src/greet.rs"
1500+ ],
1501+ "depends_on": [],
1502+ "number": 12
1503+ },
1504+ {
1505+ "title": "Show the caller's name on the web page",
1506+ "body": "Read `?name=` and pass it to `greet()`.",
1507+ "labels": [
1508+ "feature"
1509+ ],
1510+ "done": [
1511+ "The page at / shows the name given in ?name=, escaped."
1512+ ],
1513+ "files": [
1514+ "src/web.rs"
1515+ ],
1516+ "depends_on": [
1517+ 1
1518+ ],
1519+ "number": 13
1520+ }
1521+ ],
1522+ "error": null,
1523+ "author": {
1524+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1525+ "username": "syntaqx",
1526+ "kind": "user",
1527+ "verified": false,
1528+ "workspaces": []
1529+ },
1530+ "created_at": "2026-10-01T17:58:40.006Z",
1531+ "finished_at": "2026-10-01T18:01:12.774Z",
1532+ "progress": [],
1533+ "exchanges": []
1534+ },
1535+ "notes": "Each opened issue's `number` is filled in. Issues left out with `keep` stay `null`."
1536+ },
1537+ "list_pull_requests": {
1538+ "query": {
1539+ "state": "open"
1540+ },
1541+ "response": [
1542+ {
1543+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1544+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1545+ "number": 14,
1546+ "issue": 12,
1547+ "title": "Greeting should name the caller",
1548+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1549+ "agent": "claude-code",
1550+ "runtime": "external",
1551+ "status": "open",
1552+ "fork": {
1553+ "namespace": "pulls",
1554+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1555+ },
1556+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1557+ "branch": null,
1558+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1559+ "merge_base": null,
1560+ "merged_by": null,
1561+ "merged_at": null,
1562+ "superseded_by": null,
1563+ "check_status": "passed",
1564+ "files": [
1565+ {
1566+ "path": "src/main.rs",
1567+ "additions": 6,
1568+ "deletions": 2
1569+ }
1570+ ],
1571+ "assignees": [],
1572+ "reviewers": [
1573+ "ana"
1574+ ],
1575+ "team_reviewers": [],
1576+ "author": {
1577+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1578+ "username": "syntaqx",
1579+ "kind": "user",
1580+ "verified": false,
1581+ "workspaces": []
1582+ },
1583+ "requested_by": null,
1584+ "created_at": "2026-10-01T18:20:02.117Z",
1585+ "updated_at": "2026-10-01T18:35:44.902Z",
1586+ "labels": [],
1587+ "milestone": null,
1588+ "base": "main"
1589+ }
1590+ ],
1591+ "notes": "Returns at most 100 pull requests, newest first. `check_status` is `queued`, `running`, `passed`, `failed`, `errored`, or `null` when no checks have run against the head."
1592+ },
1593+ "create_pull_request": {
1594+ "request": {
1595+ "issue": 12,
1596+ "agent": "claude-code"
1597+ },
1598+ "response": {
1599+ "pull": {
1600+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1601+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1602+ "number": 14,
1603+ "issue": 12,
1604+ "title": "Greeting should name the caller",
1605+ "body": null,
1606+ "agent": "claude-code",
1607+ "runtime": "external",
1608+ "status": "draft",
1609+ "fork": {
1610+ "namespace": "pulls",
1611+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1612+ },
1613+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1614+ "branch": null,
1615+ "head_commit": null,
1616+ "merge_base": null,
1617+ "merged_by": null,
1618+ "merged_at": null,
1619+ "superseded_by": null,
1620+ "check_status": null,
1621+ "files": [],
1622+ "assignees": [],
1623+ "reviewers": [],
1624+ "labels": [],
1625+ "milestone": null,
1626+ "base": "main",
1627+ "author": {
1628+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1629+ "username": "syntaqx",
1630+ "kind": "user",
1631+ "verified": false,
1632+ "workspaces": []
1633+ },
1634+ "requested_by": null,
1635+ "created_at": "2026-10-01T18:20:02.117Z",
1636+ "updated_at": "2026-10-01T18:20:02.117Z"
1637+ },
1638+ "git": {
1639+ "remote": "https://g1t.sh/pulls/pr_01m43smh3vexsr5pmp60qwv0vs.git",
1640+ "username": "syntaqx",
1641+ "password": "your g1t access token"
1642+ }
1643+ },
1644+ "notes": "`title` defaults to the issue's title, and is required when there is no `issue`. Push to `git.remote` with your username and an access token as the password.\n\nSend `branch` to open the pull request from a branch already pushed to the repository. No fork is made, `fork` is `null`, `git.remote` is the repository itself, and the pull request is `open` at once."
1645+ },
1646+ "get_pull_request": {
1647+ "response": {
1648+ "pull": {
1649+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1650+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1651+ "number": 14,
1652+ "issue": 12,
1653+ "title": "Greeting should name the caller",
1654+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1655+ "agent": "claude-code",
1656+ "runtime": "external",
1657+ "status": "open",
1658+ "fork": {
1659+ "namespace": "pulls",
1660+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1661+ },
1662+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1663+ "branch": null,
1664+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1665+ "merge_base": null,
1666+ "merged_by": null,
1667+ "merged_at": null,
1668+ "superseded_by": null,
1669+ "check_status": "passed",
1670+ "files": [
1671+ {
1672+ "path": "src/main.rs",
1673+ "additions": 6,
1674+ "deletions": 2
1675+ }
1676+ ],
1677+ "assignees": [],
1678+ "reviewers": [
1679+ "ana"
1680+ ],
1681+ "team_reviewers": [
1682+ "flagon-io/backend"
1683+ ],
1684+ "author": {
1685+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1686+ "username": "syntaqx",
1687+ "kind": "user",
1688+ "verified": false,
1689+ "workspaces": []
1690+ },
1691+ "requested_by": null,
1692+ "created_at": "2026-10-01T18:20:02.117Z",
1693+ "updated_at": "2026-10-01T18:35:44.902Z",
1694+ "confidence": null,
1695+ "labels": [],
1696+ "milestone": null,
1697+ "base": "main"
1698+ },
1699+ "issue": {
1700+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
1701+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1702+ "number": 12,
1703+ "title": "Greeting should name the caller",
1704+ "body": "Take a name from the first argument; fall back to world.",
1705+ "labels": [
1706+ "feature"
1707+ ],
1708+ "state": "open",
1709+ "reason": null,
1710+ "resolved_by": null,
1711+ "author": {
1712+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1713+ "username": "syntaqx",
1714+ "kind": "user",
1715+ "verified": false,
1716+ "workspaces": []
1717+ },
1718+ "requested_by": null,
1719+ "created_at": "2026-10-01T18:04:11.482Z",
1720+ "updated_at": "2026-10-01T18:20:02.117Z",
1721+ "closed_at": null,
1722+ "pull_count": 1,
1723+ "comment_count": 0,
1724+ "assignees": [],
1725+ "blocked_by": [],
1726+ "queued": false,
1727+ "agent": "claude-code",
1728+ "milestone": null
1729+ },
1730+ "comments": [
1731+ {
1732+ "id": "cmt_01m43st6d0f4h8k2n6r0v4z8c2",
1733+ "kind": "event",
1734+ "author": {
1735+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1736+ "username": "syntaqx",
1737+ "kind": "user",
1738+ "verified": false,
1739+ "workspaces": []
1740+ },
1741+ "body": "marked this ready for review",
1742+ "path": null,
1743+ "line": null,
1744+ "verdict": null,
1745+ "created_at": "2026-10-01T18:33:10.420Z"
1746+ }
1747+ ],
1748+ "checks": null,
1749+ "overlaps": [],
1750+ "behind": false,
1751+ "review_pending": false,
1752+ "lifecycle": null,
1753+ "landing": false,
1754+ "stalled": null,
1755+ "messages": [
1756+ {
1757+ "id": "msg_01m43tx5egeh4t3f9zcnjenqvz",
1758+ "author": "syntaqx",
1759+ "body": "Keep \"world\" as the default when no name is given.",
1760+ "created_at": "2026-10-01T18:25:00.310Z",
1761+ "delivered_at": "2026-10-01T18:25:31.007Z",
1762+ "kind": "message",
1763+ "from_number": null,
1764+ "to_number": 14,
1765+ "answer": null,
1766+ "declined": false
1767+ }
1768+ ],
1769+ "statuses": [
1770+ {
1771+ "context": "CI / pull_request",
1772+ "state": "success",
1773+ "description": "CI passed",
1774+ "target_url": "https://g1t.sh/syntaqx/hello/actions/runs/run_01m43sw8e2g6j0m4q8t2x6a0c4",
1775+ "updated_at": "2026-10-01T18:35:44.902Z"
1776+ }
1777+ ],
1778+ "required_checks": [
1779+ {
1780+ "name": "CI",
1781+ "state": "success",
1782+ "description": "CI passed",
1783+ "target_url": "https://g1t.sh/syntaqx/hello/actions/runs/run_01m43sw8e2g6j0m4q8t2x6a0c4"
1784+ }
1785+ ],
1786+ "code_owners": {
1787+ "path": ".github/CODEOWNERS",
1788+ "required": true,
1789+ "reviews": [
1790+ {
1791+ "section": null,
1792+ "line": 3,
1793+ "pattern": "/src/",
1794+ "owners": [
1795+ "@flagon-io/backend"
1796+ ],
1797+ "files": [
1798+ "src/main.rs"
1799+ ],
1800+ "optional": false,
1801+ "required": 1,
1802+ "approved_by": [],
1803+ "changes_requested_by": [],
1804+ "satisfied": false
1805+ }
1806+ ],
1807+ "missing": "Code owners have not approved: @flagon-io/backend for /src/.",
1808+ "errors": 0
1809+ }
1810+ },
1811+ "notes": "| Field | |\n| --- | --- |\n| `pull.files` | The files it changes, with lines added and removed. |\n| `statuses` | Its checks: what each workflow run (or another tool, such as a deployment) reported on its head, as `pending`, `success`, `failure` or `error`, with a link to the run. |\n| `required_checks` | Each check the default branch requires (see [`update_repo_settings`](/reference/api/repositories/update-repo-settings/)), as it stands on the head: `success`, `failure`, `pending`, or `expected` when nothing has reported it yet. It merges only once all are `success`. |\n| `checks` | Set when the merge queue took it out, with why in `error`. Older pull requests may show a run of commands from their issue here, from before checks were workflows. |\n| `overlaps` | Other pull requests in progress that change the same files. |\n| `behind` | Whether the default branch has moved since it was made. |\n| `landing` | Whether it is being brought up to date to land. |\n| `lifecycle` | For a pull request g1t is seeing through: its stage, such as `working`, `checking`, `reviewing` or `needs_you`. |\n| `comments` | Comments, reviews and events, with `path`, `line` and `verdict`. |\n| `messages` | Messages sent to the agent working on it. |\n| `pull.reviewers`, `pull.team_reviewers` | The people asked to review it, `g1t` among them when a g1t agent was, and the teams, as `workspace/team`. Change them with [`request_reviewers`](/reference/api/pull-requests/request-reviewers/). |\n| `code_owners` | Present when the branch it merges into has a CODEOWNERS file: its `path`, whether code owners' approval is `required` there, `reviews` (one per section and rule that owns a changed file: `section`, `line`, `pattern`, `owners`, `files`, `optional`, the approvals `required`, `approved_by`, `changes_requested_by` and `satisfied`), what is still `missing`, as the merge box says it, and how many `errors` the file has; [`get_codeowners_errors`](/reference/api/repositories/get-codeowners-errors/) lists them. |\n| `mergeable` | Whether it merges cleanly into its target: `clean`, `conflicting`, `checking` (being worked out) or `unknown`. Worked out ahead of time whenever it or its target moves. |\n| `conflicts` | When `mergeable` is `conflicting`, the files that conflict. Resolve them by merging the target in, or have g1t do it. |\n| `earlier_checks` | Earlier records like `checks`, newest first. |\n\nChecks are the repository's workflows: they run on `pull_request` events when it is opened, marked ready and pushed to. Read why one failed with [`get_workflow_run`](/reference/api/actions/get-workflow-run/) and [`get_job_logs`](/reference/api/actions/get-job-logs/)."
1812+ },
1813+ "get_pull_request_changes": {
1814+ "response": {
1815+ "base": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
1816+ "head": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1817+ "files": [
1818+ {
1819+ "path": "src/main.rs",
1820+ "status": "modified",
1821+ "additions": 1,
1822+ "deletions": 1,
1823+ "binary": false,
1824+ "hunks": [
1825+ {
1826+ "lines": [
1827+ {
1828+ "kind": "context",
1829+ "old": 3,
1830+ "new": 3,
1831+ "text": "fn main() {"
1832+ },
1833+ {
1834+ "kind": "delete",
1835+ "old": 4,
1836+ "new": null,
1837+ "text": " println!(\"Hello, world!\");"
1838+ },
1839+ {
1840+ "kind": "add",
1841+ "old": null,
1842+ "new": 4,
1843+ "text": " println!(\"Hello, {}!\", std::env::args().nth(1).unwrap_or(\"world\".into()));"
1844+ },
1845+ {
1846+ "kind": "context",
1847+ "old": 5,
1848+ "new": 5,
1849+ "text": "}"
1850+ }
1851+ ]
1852+ }
1853+ ]
1854+ }
1855+ ],
1856+ "truncated": false
1857+ },
1858+ "notes": "A file's `status` is `added`, `modified` or `deleted`. A binary file has no `hunks`. In a line, `old` is `null` when it was added and `new` is `null` when it was deleted."
1859+ },
1860+ "mark_pull_request_ready": {
1861+ "request": {
1862+ "summary": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\"."
1863+ },
1864+ "response": {
1865+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1866+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1867+ "number": 14,
1868+ "issue": 12,
1869+ "title": "Greeting should name the caller",
1870+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1871+ "agent": "claude-code",
1872+ "runtime": "external",
1873+ "status": "open",
1874+ "fork": {
1875+ "namespace": "pulls",
1876+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1877+ },
1878+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1879+ "branch": null,
1880+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1881+ "merge_base": null,
1882+ "merged_by": null,
1883+ "merged_at": null,
1884+ "superseded_by": null,
1885+ "check_status": null,
1886+ "files": [
1887+ {
1888+ "path": "src/main.rs",
1889+ "additions": 6,
1890+ "deletions": 2
1891+ }
1892+ ],
1893+ "assignees": [],
1894+ "reviewers": [],
1895+ "labels": [],
1896+ "milestone": null,
1897+ "base": "main",
1898+ "author": {
1899+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1900+ "username": "syntaqx",
1901+ "kind": "user",
1902+ "verified": false,
1903+ "workspaces": []
1904+ },
1905+ "requested_by": null,
1906+ "created_at": "2026-10-01T18:20:02.117Z",
1907+ "updated_at": "2026-10-01T18:33:10.398Z"
1908+ }
1909+ },
1910+ "review_pull_request": {
1911+ "request": {
1912+ "verdict": "request_changes",
1913+ "body": "Trim the name before using it."
1914+ },
1915+ "response": {
1916+ "id": "cmt_01m43sx9f3h7k1n5r9v3z7d1g5",
1917+ "kind": "comment",
1918+ "author": {
1919+ "id": "usr_01kz9d3f7h1k5n9r3v7z1c5g9b",
1920+ "username": "ana",
1921+ "kind": "user",
1922+ "verified": true,
1923+ "workspaces": [
1924+ {
1925+ "slug": "flagon-io",
1926+ "role": "member"
1927+ }
1928+ ]
1929+ },
1930+ "body": "Trim the name before using it.",
1931+ "path": null,
1932+ "line": null,
1933+ "verdict": "request_changes",
1934+ "created_at": "2026-10-01T18:40:05.019Z"
1935+ }
1936+ },
1937+ "request_reviewers": {
1938+ "params": {
1939+ "owner": "flagon-io",
1940+ "name": "hello",
1941+ "number": 14
1942+ },
1943+ "request": {
1944+ "reviewers": [
1945+ "bo"
1946+ ],
1947+ "team_reviewers": [
1948+ "backend"
1949+ ]
1950+ },
1951+ "response": {
1952+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
1953+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
1954+ "number": 14,
1955+ "issue": 12,
1956+ "title": "Greeting should name the caller",
1957+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
1958+ "agent": "claude-code",
1959+ "runtime": "external",
1960+ "status": "open",
1961+ "fork": {
1962+ "namespace": "pulls",
1963+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
1964+ },
1965+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
1966+ "branch": null,
1967+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
1968+ "merge_base": null,
1969+ "merged_by": null,
1970+ "merged_at": null,
1971+ "superseded_by": null,
1972+ "check_status": "passed",
1973+ "files": [
1974+ {
1975+ "path": "src/main.rs",
1976+ "additions": 6,
1977+ "deletions": 2
1978+ }
1979+ ],
1980+ "assignees": [],
1981+ "reviewers": [
1982+ "ana",
1983+ "bo"
1984+ ],
1985+ "team_reviewers": [
1986+ "flagon-io/backend"
1987+ ],
1988+ "author": {
1989+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
1990+ "username": "syntaqx",
1991+ "kind": "user",
1992+ "verified": false,
1993+ "workspaces": []
1994+ },
1995+ "requested_by": null,
1996+ "created_at": "2026-10-01T18:20:02.117Z",
1997+ "updated_at": "2026-10-01T18:40:12.331Z"
1998+ },
1999+ "notes": "Adds to who is asked: `reviewers` by username (`g1t` asks a g1t agent), `team_reviewers` as `workspace/team`, or a team's slug in the repository's workspace. A team with review assignment on has the people it picks added to `reviewers`, and stays in `team_reviewers`. Each is told in their inbox. Nobody is asked to review their own pull request. `422` for someone who is not an account, or a team that does not exist or that you cannot see. Whoever opened it, or the Triage role or higher, while it is open. See [Pull requests](/guides/pull-requests/) and [Teams](/guides/teams/)."
2000+ },
2001+ "remove_requested_reviewers": {
2002+ "params": {
2003+ "owner": "flagon-io",
2004+ "name": "hello",
2005+ "number": 14
2006+ },
2007+ "request": {
2008+ "reviewers": [
2009+ "bo"
2010+ ],
2011+ "team_reviewers": [
2012+ "flagon-io/backend"
2013+ ]
2014+ },
2015+ "response": {
2016+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
2017+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
2018+ "number": 14,
2019+ "issue": 12,
2020+ "title": "Greeting should name the caller",
2021+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
2022+ "agent": "claude-code",
2023+ "runtime": "external",
2024+ "status": "open",
2025+ "fork": {
2026+ "namespace": "pulls",
2027+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
2028+ },
2029+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
2030+ "branch": null,
2031+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2032+ "merge_base": null,
2033+ "merged_by": null,
2034+ "merged_at": null,
2035+ "superseded_by": null,
2036+ "check_status": "passed",
2037+ "files": [
2038+ {
2039+ "path": "src/main.rs",
2040+ "additions": 6,
2041+ "deletions": 2
2042+ }
2043+ ],
2044+ "assignees": [],
2045+ "reviewers": [
2046+ "ana"
2047+ ],
2048+ "team_reviewers": [],
2049+ "author": {
2050+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
2051+ "username": "syntaqx",
2052+ "kind": "user",
2053+ "verified": false,
2054+ "workspaces": []
2055+ },
2056+ "requested_by": null,
2057+ "created_at": "2026-10-01T18:20:02.117Z",
2058+ "updated_at": "2026-10-01T18:41:30.904Z"
2059+ },
2060+ "notes": "Takes them off who is asked; anyone not asked is ignored. Reviews they already gave stay, as do the people a team's review assignment picked: remove them by username."
2061+ },
2062+ "merge_pull_request": {
2063+ "request": {
2064+ "keep_issue_open": false
2065+ },
2066+ "response": {
2067+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
2068+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
2069+ "number": 14,
2070+ "issue": 12,
2071+ "title": "Greeting should name the caller",
2072+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
2073+ "agent": "claude-code",
2074+ "runtime": "external",
2075+ "status": "merged",
2076+ "fork": {
2077+ "namespace": "pulls",
2078+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
2079+ },
2080+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
2081+ "branch": null,
2082+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2083+ "merge_base": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
2084+ "merged_by": "syntaqx",
2085+ "merged_at": "2026-10-01T18:52:17.093Z",
2086+ "superseded_by": null,
2087+ "check_status": "passed",
2088+ "files": [
2089+ {
2090+ "path": "src/main.rs",
2091+ "additions": 6,
2092+ "deletions": 2
2093+ }
2094+ ],
2095+ "assignees": [],
2096+ "reviewers": [
2097+ "ana"
2098+ ],
2099+ "labels": [],
2100+ "milestone": null,
2101+ "base": "main",
2102+ "author": {
2103+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
2104+ "username": "syntaqx",
2105+ "kind": "user",
2106+ "verified": false,
2107+ "workspaces": []
2108+ },
2109+ "requested_by": null,
2110+ "created_at": "2026-10-01T18:20:02.117Z",
2111+ "updated_at": "2026-10-01T18:52:17.093Z"
2112+ },
2113+ "notes": "A draft, or one whose checks have not passed, answers `409`. A pull request still `open` in the response has not landed yet: `landing` is true on it while it is brought up to date, and [get the merge queue](/reference/api/pull-requests/get-merge-queue/) shows it waiting in the [merge queue](/guides/merge-queue/). Merging records the pull request in the issue's `resolved_by` and sets `superseded_by` on the pull requests it closes."
2114+ },
2115+ "close_pull_request": {
2116+ "response": {
2117+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
2118+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
2119+ "number": 14,
2120+ "issue": 12,
2121+ "title": "Greeting should name the caller",
2122+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
2123+ "agent": "claude-code",
2124+ "runtime": "external",
2125+ "status": "closed",
2126+ "fork": {
2127+ "namespace": "pulls",
2128+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
2129+ },
2130+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
2131+ "branch": null,
2132+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2133+ "merge_base": null,
2134+ "merged_by": null,
2135+ "merged_at": null,
2136+ "superseded_by": null,
2137+ "check_status": null,
2138+ "files": [
2139+ {
2140+ "path": "src/main.rs",
2141+ "additions": 6,
2142+ "deletions": 2
2143+ }
2144+ ],
2145+ "assignees": [],
2146+ "reviewers": [],
2147+ "labels": [],
2148+ "milestone": null,
2149+ "base": "main",
2150+ "author": {
2151+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
2152+ "username": "syntaqx",
2153+ "kind": "user",
2154+ "verified": false,
2155+ "workspaces": []
2156+ },
2157+ "requested_by": null,
2158+ "created_at": "2026-10-01T18:20:02.117Z",
2159+ "updated_at": "2026-10-01T19:02:48.760Z"
2160+ }
2161+ },
2162+ "get_merge_queue": {
2163+ "response": {
2164+ "enabled": true,
2165+ "active": [
2166+ {
2167+ "id": "qen_01m43rn0qsft1tpap1awkewzbb",
2168+ "number": 14,
2169+ "title": "Greeting should name the caller",
2170+ "agent": "claude-code",
2171+ "state": "testing",
2172+ "ahead": [],
2173+ "base_commit": "3a7e9c1b5d2f4a6c8e0b2d4f6a8c0e2b4d6f8a1c",
2174+ "combined_commit": null,
2175+ "error": null,
2176+ "results": [],
2177+ "enqueued_by": "syntaqx",
2178+ "created_at": "2026-10-04T15:31:20.441Z",
2179+ "finished_at": null
2180+ }
2181+ ],
2182+ "recent": [
2183+ {
2184+ "id": "qen_01m43khqjmeb5a1magayrnk63z",
2185+ "number": 11,
2186+ "title": "Fix trailing newline in greeting",
2187+ "agent": "g1t",
2188+ "state": "landed",
2189+ "ahead": [],
2190+ "base_commit": "4b1d7e9c2a5f8e3d6c0b9a7e5d3c1b8a6f4e2d0c",
2191+ "combined_commit": "c3e8a1f6d4b2097e5c3a1f8d6b4e2c0a9f7d5b3e",
2192+ "error": null,
2193+ "results": [
2194+ {
2195+ "command": "cargo test",
2196+ "passed": true,
2197+ "exit_code": 0,
2198+ "output": "test result: ok. 12 passed; 0 failed\n",
2199+ "duration_ms": 48211
2200+ }
2201+ ],
2202+ "enqueued_by": "g1t",
2203+ "created_at": "2026-10-04T14:02:09.876Z",
2204+ "finished_at": "2026-10-04T14:09:55.102Z"
2205+ }
2206+ ]
2207+ },
2208+ "notes": "An entry's `state` is `waiting`, `testing`, `passed`, `failed`, `landed` or `removed`. `active` is in queue order; `recent` holds at most 20, newest first."
2209+ },
2210+ "message_agent": {
2211+ "request": {
2212+ "body": "Keep \"world\" as the default when no name is given."
2213+ },
2214+ "response": {
2215+ "id": "msg_01m43tx5egeh4t3f9zcnjenqvz",
2216+ "author": "syntaqx",
2217+ "body": "Keep \"world\" as the default when no name is given.",
2218+ "created_at": "2026-10-01T18:25:00.310Z",
2219+ "delivered_at": null,
2220+ "kind": "message",
2221+ "from_number": null,
2222+ "to_number": 14,
2223+ "answer": null,
2224+ "declined": false
2225+ },
2226+ "notes": "The response is the message. `delivered_at` is set once the agent has read it."
2227+ },
2228+ "answer_message": {
2229+ "params": {
2230+ "id": "msg_01m43t66tde8hs2vpxhh3v8tqw"
2231+ },
2232+ "request": {
2233+ "body": "No. greet() keeps its name; only greet_named() is added."
2234+ },
2235+ "response": {
2236+ "id": "msg_01m43t66tde8hs2vpxhh3v8tqw",
2237+ "author": "g1t",
2238+ "body": "Are you renaming greet() in src/lib.rs? I need to call it from #16.",
2239+ "created_at": "2026-10-01T18:58:12.301Z",
2240+ "delivered_at": "2026-10-01T18:58:40.117Z",
2241+ "kind": "question",
2242+ "from_number": 16,
2243+ "to_number": 14,
2244+ "answer": "No. greet() keeps its name; only greet_named() is added.",
2245+ "declined": false
2246+ },
2247+ "notes": "The response is the question or handoff that was answered, with `answer` and `declined` filled in."
2248+ },
2249+ "take_messages": {
2250+ "response": [
2251+ {
2252+ "id": "msg_01m43tx5egeh4t3f9zcnjenqvz",
2253+ "author": "syntaqx",
2254+ "body": "Keep \"world\" as the default when no name is given.",
2255+ "created_at": "2026-10-01T18:25:00.310Z",
2256+ "delivered_at": "2026-10-01T18:25:31.007Z",
2257+ "kind": "message",
2258+ "from_number": null,
2259+ "to_number": 14,
2260+ "answer": null,
2261+ "declined": false
2262+ }
2263+ ],
2264+ "notes": "Only a g1t agent's token can take messages. They come oldest first, and each is marked delivered."
2265+ },
2266+ "read_session": {
2267+ "query": {
2268+ "after": 0
2269+ },
2270+ "response": [
2271+ {
2272+ "seq": 1,
2273+ "kind": "prompt",
2274+ "text": "Make the greeting name the caller (issue #12).",
2275+ "tool": null,
2276+ "commit": null,
2277+ "at": "2026-10-01T18:21:00.004Z"
2278+ },
2279+ {
2280+ "seq": 2,
2281+ "kind": "tool_call",
2282+ "text": "cargo test",
2283+ "tool": "bash",
2284+ "commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2285+ "at": "2026-10-01T18:30:12.660Z"
2286+ }
2287+ ]
2288+ },
2289+ "record_session": {
2290+ "request": {
2291+ "entries": [
2292+ {
2293+ "kind": "message",
2294+ "text": "Reading src/main.rs."
2295+ },
2296+ {
2297+ "kind": "tool_call",
2298+ "text": "cargo test",
2299+ "tool": "bash"
2300+ }
2301+ ]
2302+ },
2303+ "response": {
2304+ "count": 2
2305+ },
2306+ "notes": "Up to 200 entries can be appended per request. Each is recorded against the pull request's head commit at the time. See [sessions and why-blame](/guides/why-blame/)."
2307+ },
2308+ "list_workflows": {
2309+ "response": [
2310+ {
2311+ "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2312+ "path": ".g1t/workflows/ci.yml",
2313+ "name": "CI",
2314+ "events": [
2315+ "push",
2316+ "pull_request",
2317+ "workflow_dispatch"
2318+ ],
2319+ "state": "active",
2320+ "error": null,
2321+ "notes": [
2322+ {
2323+ "severity": "unsupported",
2324+ "job": "test",
2325+ "message": "`services` containers (such as a database) are not started on g1t yet."
2326+ }
2327+ ],
2328+ "dispatch": {
2329+ "debug": {
2330+ "description": "Verbose logs",
2331+ "type": "boolean",
2332+ "default": false
2333+ }
2334+ },
2335+ "last_run": {
2336+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2337+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2338+ "path": ".g1t/workflows/ci.yml",
2339+ "name": "CI",
2340+ "title": "Greeting should name the caller",
2341+ "number": 12,
2342+ "attempt": 1,
2343+ "event": "push",
2344+ "ref": "refs/heads/main",
2345+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2346+ "pull": null,
2347+ "status": "completed",
2348+ "conclusion": "success",
2349+ "error": null,
2350+ "actor": "syntaqx",
2351+ "created_at": "2026-10-04T15:42:07.318Z",
2352+ "started_at": "2026-10-04T15:42:09.020Z",
2353+ "finished_at": "2026-10-04T15:44:31.877Z"
2354+ }
2355+ },
2356+ {
2357+ "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2358+ "path": ".g1t/workflows/nightly.yml",
2359+ "name": "Nightly",
2360+ "events": [
2361+ "schedule"
2362+ ],
2363+ "state": "disabled",
2364+ "error": null,
2365+ "notes": [],
2366+ "dispatch": null,
2367+ "last_run": null
2368+ }
2369+ ],
2370+ "notes": "`state` is `active` or `disabled`. `dispatch` holds the `workflow_dispatch` inputs, or is `null` when the workflow cannot be run by hand. See [GitHub Actions](/guides/actions/)."
2371+ },
2372+ "list_workflow_runs": {
2373+ "query": {
2374+ "workflow": "ci.yml",
2375+ "branch": "main",
2376+ "per_page": 20
2377+ },
2378+ "response": [
2379+ {
2380+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2381+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2382+ "path": ".g1t/workflows/ci.yml",
2383+ "name": "CI",
2384+ "title": "Greeting should name the caller",
2385+ "number": 12,
2386+ "attempt": 1,
2387+ "event": "push",
2388+ "ref": "refs/heads/main",
2389+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2390+ "pull": null,
2391+ "status": "completed",
2392+ "conclusion": "success",
2393+ "error": null,
2394+ "actor": "syntaqx",
2395+ "created_at": "2026-10-04T15:42:07.318Z",
2396+ "started_at": "2026-10-04T15:42:09.020Z",
2397+ "finished_at": "2026-10-04T15:44:31.877Z"
2398+ }
2399+ ],
2400+ "notes": "A run's `status` is `queued`, `pending` (waiting for its concurrency group), `in_progress` or `completed`; `conclusion` is set once it completes."
2401+ },
2402+ "list_runs_of_workflow": {
2403+ "params": {
2404+ "workflow": "ci.yml"
2405+ },
2406+ "query": {
2407+ "branch": "main",
2408+ "per_page": 20
2409+ },
2410+ "response": [
2411+ {
2412+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2413+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2414+ "path": ".g1t/workflows/ci.yml",
2415+ "name": "CI",
2416+ "title": "Greeting should name the caller",
2417+ "number": 12,
2418+ "attempt": 1,
2419+ "event": "push",
2420+ "ref": "refs/heads/main",
2421+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2422+ "pull": null,
2423+ "status": "completed",
2424+ "conclusion": "success",
2425+ "error": null,
2426+ "actor": "syntaqx",
2427+ "created_at": "2026-10-04T15:42:07.318Z",
2428+ "started_at": "2026-10-04T15:42:09.020Z",
2429+ "finished_at": "2026-10-04T15:44:31.877Z"
2430+ }
2431+ ]
2432+ },
2433+ "get_workflow_run": {
2434+ "params": {
2435+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2436+ },
2437+ "response": {
2438+ "run": {
2439+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2440+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2441+ "path": ".g1t/workflows/ci.yml",
2442+ "name": "CI",
2443+ "title": "Greeting should name the caller",
2444+ "number": 12,
2445+ "attempt": 1,
2446+ "event": "push",
2447+ "ref": "refs/heads/main",
2448+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2449+ "pull": null,
2450+ "status": "completed",
2451+ "conclusion": "failure",
2452+ "error": null,
2453+ "actor": "syntaqx",
2454+ "created_at": "2026-10-04T15:42:07.318Z",
2455+ "started_at": "2026-10-04T15:42:09.020Z",
2456+ "finished_at": "2026-10-04T15:44:31.877Z"
2457+ },
2458+ "jobs": [
2459+ {
2460+ "id": "job_01kpx7b3d0e4f8g2h6j0k4m8ns",
2461+ "run_id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2462+ "key": "test",
2463+ "name": "test",
2464+ "needs": [],
2465+ "status": "completed",
2466+ "conclusion": "failure",
2467+ "steps": [
2468+ {
2469+ "number": 1,
2470+ "name": "Run actions/checkout@v4",
2471+ "status": "completed",
2472+ "conclusion": "success",
2473+ "started_at": "2026-10-04T15:42:10.101Z",
2474+ "finished_at": "2026-10-04T15:42:12.433Z"
2475+ },
2476+ {
2477+ "number": 2,
2478+ "name": "Run cargo test",
2479+ "status": "completed",
2480+ "conclusion": "failure",
2481+ "started_at": "2026-10-04T15:42:12.440Z",
2482+ "finished_at": "2026-10-04T15:44:30.902Z"
2483+ }
2484+ ],
2485+ "annotations": [
2486+ {
2487+ "level": "error",
2488+ "message": "assertion failed: greeting names the caller",
2489+ "title": "greet",
2490+ "file": "src/main.rs",
2491+ "line": 41
2492+ }
2493+ ],
2494+ "reason": null,
2495+ "started_at": "2026-10-04T15:42:09.020Z",
2496+ "finished_at": "2026-10-04T15:44:31.002Z"
2497+ },
2498+ {
2499+ "id": "job_01kpx7b3d0e4f8g2h6j0k4m8nt",
2500+ "run_id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2501+ "key": "deploy",
2502+ "name": "deploy",
2503+ "needs": [
2504+ "test"
2505+ ],
2506+ "status": "completed",
2507+ "conclusion": "skipped",
2508+ "steps": [],
2509+ "annotations": [],
2510+ "reason": "A job it needs did not succeed.",
2511+ "started_at": null,
2512+ "finished_at": "2026-10-04T15:44:31.877Z"
2513+ }
2514+ ],
2515+ "notes": [
2516+ {
2517+ "severity": "unsupported",
2518+ "job": "test",
2519+ "message": "`services` containers (such as a database) are not started on g1t yet."
2520+ }
2521+ ]
2522+ }
2523+ },
2524+ "get_job_logs": {
2525+ "params": {
2526+ "job": "job_01kpx7b3d0e4f8g2h6j0k4m8ns"
2527+ },
2528+ "query": {
2529+ "after": 0
2530+ },
2531+ "response": {
2532+ "chunks": [
2533+ {
2534+ "seq": 1,
2535+ "step": 0,
2536+ "text": "Preparing the sandbox\n"
2537+ },
2538+ {
2539+ "seq": 2,
2540+ "step": 2,
2541+ "text": "> cargo test\ntest greet ... FAILED\n"
2542+ }
2543+ ],
2544+ "done": true
2545+ },
2546+ "notes": "Returns at most 500 chunks. Step 0 is the job's setup. While `done` is false, call again with the last `seq` as `after`."
2547+ },
2548+ "dispatch_workflow": {
2549+ "params": {
2550+ "workflow": "ci.yml"
2551+ },
2552+ "request": {
2553+ "ref": "main",
2554+ "inputs": {
2555+ "debug": true
2556+ }
2557+ },
2558+ "response": {
2559+ "id": "run_01kpx8d4e7f0g3h6j9k2m5n8pq",
2560+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2561+ "path": ".g1t/workflows/ci.yml",
2562+ "name": "CI",
2563+ "title": "CI run by syntaqx",
2564+ "number": 13,
2565+ "attempt": 1,
2566+ "event": "workflow_dispatch",
2567+ "ref": "refs/heads/main",
2568+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2569+ "pull": null,
2570+ "status": "queued",
2571+ "conclusion": null,
2572+ "error": null,
2573+ "actor": "syntaqx",
2574+ "created_at": "2026-10-04T16:30:00.512Z",
2575+ "started_at": null,
2576+ "finished_at": null
2577+ }
2578+ },
2579+ "cancel_workflow_run": {
2580+ "params": {
2581+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2582+ },
2583+ "response": {
2584+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2585+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2586+ "path": ".g1t/workflows/ci.yml",
2587+ "name": "CI",
2588+ "title": "Greeting should name the caller",
2589+ "number": 12,
2590+ "attempt": 1,
2591+ "event": "push",
2592+ "ref": "refs/heads/main",
2593+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2594+ "pull": null,
2595+ "status": "completed",
2596+ "conclusion": "cancelled",
2597+ "error": null,
2598+ "actor": "syntaqx",
2599+ "created_at": "2026-10-04T15:42:07.318Z",
2600+ "started_at": "2026-10-04T15:42:09.020Z",
2601+ "finished_at": "2026-10-04T15:44:31.877Z"
2602+ }
2603+ },
2604+ "rerun_workflow_run": {
2605+ "params": {
2606+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2607+ },
2608+ "request": {
2609+ "failed_only": true
2610+ },
2611+ "response": {
2612+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2613+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2614+ "path": ".g1t/workflows/ci.yml",
2615+ "name": "CI",
2616+ "title": "Greeting should name the caller",
2617+ "number": 12,
2618+ "attempt": 2,
2619+ "event": "push",
2620+ "ref": "refs/heads/main",
2621+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2622+ "pull": null,
2623+ "status": "queued",
2624+ "conclusion": null,
2625+ "error": null,
2626+ "actor": "syntaqx",
2627+ "created_at": "2026-10-04T15:42:07.318Z",
2628+ "started_at": null,
2629+ "finished_at": null
2630+ },
2631+ "notes": "The run keeps its id; `attempt` goes up by one."
2632+ },
2633+ "rerun_failed_jobs": {
2634+ "params": {
2635+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr"
2636+ },
2637+ "response": {
2638+ "id": "run_01kpx7b3c6d9e2f5g8h1j4k7mr",
2639+ "workflow_id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9np",
2640+ "path": ".g1t/workflows/ci.yml",
2641+ "name": "CI",
2642+ "title": "Greeting should name the caller",
2643+ "number": 12,
2644+ "attempt": 2,
2645+ "event": "push",
2646+ "ref": "refs/heads/main",
2647+ "sha": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
2648+ "pull": null,
2649+ "status": "queued",
2650+ "conclusion": null,
2651+ "error": null,
2652+ "actor": "syntaqx",
2653+ "created_at": "2026-10-04T15:42:07.318Z",
2654+ "started_at": null,
2655+ "finished_at": null
2656+ }
2657+ },
2658+ "update_workflow": {
2659+ "params": {
2660+ "workflow": "nightly.yml"
2661+ },
2662+ "request": {
2663+ "enabled": false
2664+ },
2665+ "response": {
2666+ "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2667+ "path": ".g1t/workflows/nightly.yml",
2668+ "name": "Nightly",
2669+ "events": [
2670+ "schedule"
2671+ ],
2672+ "state": "disabled",
2673+ "error": null,
2674+ "notes": [],
2675+ "dispatch": null,
2676+ "last_run": null
2677+ }
2678+ },
2679+ "enable_workflow": {
2680+ "params": {
2681+ "workflow": "nightly.yml"
2682+ },
2683+ "response": {
2684+ "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2685+ "path": ".g1t/workflows/nightly.yml",
2686+ "name": "Nightly",
2687+ "events": [
2688+ "schedule"
2689+ ],
2690+ "state": "active",
2691+ "error": null,
2692+ "notes": [],
2693+ "dispatch": null,
2694+ "last_run": null
2695+ }
2696+ },
2697+ "disable_workflow": {
2698+ "params": {
2699+ "workflow": "nightly.yml"
2700+ },
2701+ "response": {
2702+ "id": "wfl_01kpw2c5d8e1f4g7h0j3k6m9nq",
2703+ "path": ".g1t/workflows/nightly.yml",
2704+ "name": "Nightly",
2705+ "events": [
2706+ "schedule"
2707+ ],
2708+ "state": "disabled",
2709+ "error": null,
2710+ "notes": [],
2711+ "dispatch": null,
2712+ "last_run": null
2713+ }
2714+ },
2715+ "list_actions_secrets": {
2716+ "response": [
2717+ {
2718+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ab",
2719+ "name": "NPM_TOKEN",
2720+ "kind": "secret",
2721+ "value": null,
2722+ "scope": "workspace",
2723+ "updated_at": "2026-10-01T09:12:44.020Z",
2724+ "available_to": [
2725+ "workflows"
2726+ ],
2727+ "environments": [],
2728+ "projects": [],
2729+ "note": null,
2730+ "updated_by": "syntaqx"
2731+ },
2732+ {
2733+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ac",
2734+ "name": "STRIPE_KEY",
2735+ "kind": "secret",
2736+ "value": null,
2737+ "scope": "project",
2738+ "updated_at": "2026-10-04T15:42:07.318Z",
2739+ "available_to": [
2740+ "workflows",
2741+ "deployments"
2742+ ],
2743+ "environments": [
2744+ "production"
2745+ ],
2746+ "projects": [],
2747+ "note": "Rotate in the Stripe dashboard.",
2748+ "updated_by": "syntaqx"
2749+ }
2750+ ],
2751+ "notes": "Values are never returned. A repository's list includes the workspace's rows that reach it, with `scope` set to `workspace`. Empty `environments` means every environment."
2752+ },
2753+ "list_actions_secrets_for_workspace": {
2754+ "params": {
2755+ "workspace": "flagon-io"
2756+ },
2757+ "response": [
2758+ {
2759+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ab",
2760+ "name": "NPM_TOKEN",
2761+ "kind": "secret",
2762+ "value": null,
2763+ "scope": "workspace",
2764+ "updated_at": "2026-10-04T15:42:07.318Z",
2765+ "available_to": [
2766+ "workflows"
2767+ ],
2768+ "environments": [],
2769+ "projects": [],
2770+ "note": null,
2771+ "updated_by": "syntaqx"
2772+ }
2773+ ],
2774+ "notes": "Values are never returned. A repository's list includes the workspace's rows that reach it, with `scope` set to `workspace`. Empty `environments` means every environment."
2775+ },
2776+ "set_actions_secret": {
2777+ "params": {
2778+ "setting": "STRIPE_KEY"
2779+ },
2780+ "request": {
2781+ "value": "sk_live_…",
2782+ "available_to": [
2783+ "workflows",
2784+ "deployments"
2785+ ],
2786+ "environments": [
2787+ "production"
2788+ ]
2789+ },
2790+ "response": {
2791+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ac",
2792+ "name": "STRIPE_KEY",
2793+ "kind": "secret",
2794+ "value": null,
2795+ "scope": "project",
2796+ "updated_at": "2026-10-04T15:42:07.318Z",
2797+ "available_to": [
2798+ "workflows",
2799+ "deployments"
2800+ ],
2801+ "environments": [
2802+ "production"
2803+ ],
2804+ "projects": [],
2805+ "note": null,
2806+ "updated_by": "syntaqx"
2807+ },
2808+ "notes": "Keys are uppercased. See [secrets and variables](/guides/secrets-and-variables/)."
2809+ },
2810+ "set_actions_secret_for_workspace": {
2811+ "params": {
2812+ "workspace": "flagon-io",
2813+ "setting": "NPM_TOKEN"
2814+ },
2815+ "request": {
2816+ "value": "npm_…",
2817+ "projects": [
2818+ "hello"
2819+ ]
2820+ },
2821+ "response": {
2822+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ac",
2823+ "name": "NPM_TOKEN",
2824+ "kind": "secret",
2825+ "value": null,
2826+ "scope": "workspace",
2827+ "updated_at": "2026-10-04T15:42:07.318Z",
2828+ "available_to": [
2829+ "workflows"
2830+ ],
2831+ "environments": [],
2832+ "projects": [
2833+ "hello"
2834+ ],
2835+ "note": null,
2836+ "updated_by": "syntaqx"
2837+ }
2838+ },
2839+ "delete_actions_secret": {
2840+ "params": {
2841+ "setting": "STRIPE_KEY"
2842+ },
2843+ "response": true
2844+ },
2845+ "delete_actions_secret_for_workspace": {
2846+ "params": {
2847+ "workspace": "flagon-io",
2848+ "setting": "NPM_TOKEN"
2849+ },
2850+ "response": true
2851+ },
2852+ "list_actions_variables": {
2853+ "response": [
2854+ {
2855+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2856+ "name": "NODE_VERSION",
2857+ "kind": "variable",
2858+ "value": "20",
2859+ "scope": "project",
2860+ "updated_at": "2026-10-04T15:42:07.318Z",
2861+ "available_to": [
2862+ "workflows",
2863+ "deployments"
2864+ ],
2865+ "environments": [],
2866+ "projects": [],
2867+ "note": null,
2868+ "updated_by": "syntaqx"
2869+ }
2870+ ],
2871+ "notes": "A repository's list includes the workspace's rows that reach it, with `scope` set to `workspace`. Empty `environments` means every environment."
2872+ },
2873+ "list_actions_variables_for_workspace": {
2874+ "params": {
2875+ "workspace": "flagon-io"
2876+ },
2877+ "response": [
2878+ {
2879+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2880+ "name": "NODE_VERSION",
2881+ "kind": "variable",
2882+ "value": "20",
2883+ "scope": "workspace",
2884+ "updated_at": "2026-10-04T15:42:07.318Z",
2885+ "available_to": [
2886+ "workflows",
2887+ "deployments"
2888+ ],
2889+ "environments": [],
2890+ "projects": [],
2891+ "note": null,
2892+ "updated_by": "syntaqx"
2893+ }
2894+ ]
2895+ },
2896+ "set_actions_variable": {
2897+ "request": {
2898+ "setting": "NODE_VERSION",
2899+ "value": "20"
2900+ },
2901+ "response": {
2902+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2903+ "name": "NODE_VERSION",
2904+ "kind": "variable",
2905+ "value": "20",
2906+ "scope": "project",
2907+ "updated_at": "2026-10-04T15:42:07.318Z",
2908+ "available_to": [
2909+ "workflows",
2910+ "deployments"
2911+ ],
2912+ "environments": [],
2913+ "projects": [],
2914+ "note": null,
2915+ "updated_by": "syntaqx"
2916+ },
2917+ "notes": "GitHub's clients send the key as `name`; that is accepted too."
2918+ },
2919+ "set_actions_variable_for_workspace": {
2920+ "params": {
2921+ "workspace": "flagon-io"
2922+ },
2923+ "request": {
2924+ "setting": "NODE_VERSION",
2925+ "value": "20"
2926+ },
2927+ "response": {
2928+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2929+ "name": "NODE_VERSION",
2930+ "kind": "variable",
2931+ "value": "20",
2932+ "scope": "workspace",
2933+ "updated_at": "2026-10-04T15:42:07.318Z",
2934+ "available_to": [
2935+ "workflows",
2936+ "deployments"
2937+ ],
2938+ "environments": [],
2939+ "projects": [],
2940+ "note": null,
2941+ "updated_by": "syntaqx"
2942+ }
2943+ },
2944+ "update_actions_variable": {
2945+ "params": {
2946+ "setting": "NODE_VERSION"
2947+ },
2948+ "request": {
2949+ "value": "22"
2950+ },
2951+ "response": {
2952+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2953+ "name": "NODE_VERSION",
2954+ "kind": "variable",
2955+ "value": "22",
2956+ "scope": "project",
2957+ "updated_at": "2026-10-04T15:42:07.318Z",
2958+ "available_to": [
2959+ "workflows",
2960+ "deployments"
2961+ ],
2962+ "environments": [],
2963+ "projects": [],
2964+ "note": null,
2965+ "updated_by": "syntaqx"
2966+ }
2967+ },
2968+ "update_actions_variable_for_workspace": {
2969+ "params": {
2970+ "workspace": "flagon-io",
2971+ "setting": "NODE_VERSION"
2972+ },
2973+ "request": {
2974+ "value": "22"
2975+ },
2976+ "response": {
2977+ "id": "set_01kpv9q4r7s0t3v6w9x2y5z8ad",
2978+ "name": "NODE_VERSION",
2979+ "kind": "variable",
2980+ "value": "22",
2981+ "scope": "workspace",
2982+ "updated_at": "2026-10-04T15:42:07.318Z",
2983+ "available_to": [
2984+ "workflows",
2985+ "deployments"
2986+ ],
2987+ "environments": [],
2988+ "projects": [],
2989+ "note": null,
2990+ "updated_by": "syntaqx"
2991+ }
2992+ },
2993+ "delete_actions_variable": {
2994+ "params": {
2995+ "setting": "NODE_VERSION"
2996+ },
2997+ "response": true
2998+ },
2999+ "delete_actions_variable_for_workspace": {
3000+ "params": {
3001+ "workspace": "flagon-io",
3002+ "setting": "NODE_VERSION"
3003+ },
3004+ "response": true
3005+ },
3006+ "list_runners": {
3007+ "response": [
3008+ {
3009+ "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z",
3010+ "name": "build-01",
3011+ "workspace": "flagon-io",
3012+ "repo": null,
3013+ "group": "Default",
3014+ "labels": [
3015+ "self-hosted",
3016+ "linux",
3017+ "x64",
3018+ "gpu"
3019+ ],
3020+ "os": "linux",
3021+ "arch": "x64",
3022+ "version": "0.2.0",
3023+ "ephemeral": false,
3024+ "status": "busy",
3025+ "work": {
3026+ "kind": "workflow",
3027+ "id": "job_01kq2m9b1d4g7j0m3p6s9v2y5b",
3028+ "name": "test (linux, 24)",
3029+ "repo": "flagon-io/hello",
3030+ "run_id": "run_01kq2m9a8c1f4h7k0n3q6t9w2z",
3031+ "started_at": "2026-10-06T14:02:11.000Z"
3032+ },
3033+ "last_seen_at": "2026-10-06T14:05:40.512Z",
3034+ "created_at": "2026-10-02T09:30:00.000Z",
3035+ "created_by": null
3036+ },
3037+ {
3038+ "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w9a",
3039+ "name": "mac-mini",
3040+ "workspace": "flagon-io",
3041+ "repo": null,
3042+ "group": "Default",
3043+ "labels": [
3044+ "self-hosted",
3045+ "macos",
3046+ "arm64"
3047+ ],
3048+ "os": "macos",
3049+ "arch": "arm64",
3050+ "version": "0.2.0",
3051+ "ephemeral": false,
3052+ "status": "online",
3053+ "work": null,
3054+ "last_seen_at": "2026-10-06T14:05:40.512Z",
3055+ "created_at": "2026-10-02T09:30:00.000Z",
3056+ "created_by": null
3057+ }
3058+ ],
3059+ "notes": "A repository's list holds its own runners (`repo` set) and the workspace's that its runner group lets it use. A runner is `offline` when it has not polled for 90 seconds."
3060+ },
3061+ "list_runners_for_workspace": {
3062+ "params": {
3063+ "workspace": "flagon-io"
3064+ },
3065+ "response": [
3066+ {
3067+ "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z",
3068+ "name": "build-01",
3069+ "workspace": "flagon-io",
3070+ "repo": null,
3071+ "group": "Default",
3072+ "labels": [
3073+ "self-hosted",
3074+ "linux",
3075+ "x64",
3076+ "gpu"
3077+ ],
3078+ "os": "linux",
3079+ "arch": "x64",
3080+ "version": "0.2.0",
3081+ "ephemeral": false,
3082+ "status": "busy",
3083+ "work": {
3084+ "kind": "workflow",
3085+ "id": "job_01kq2m9b1d4g7j0m3p6s9v2y5b",
3086+ "name": "test (linux, 24)",
3087+ "repo": "flagon-io/hello",
3088+ "run_id": "run_01kq2m9a8c1f4h7k0n3q6t9w2z",
3089+ "started_at": "2026-10-06T14:02:11.000Z"
3090+ },
3091+ "last_seen_at": "2026-10-06T14:05:40.512Z",
3092+ "created_at": "2026-10-02T09:30:00.000Z",
3093+ "created_by": null
3094+ },
3095+ {
3096+ "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w9a",
3097+ "name": "mac-mini",
3098+ "workspace": "flagon-io",
3099+ "repo": null,
3100+ "group": "Default",
3101+ "labels": [
3102+ "self-hosted",
3103+ "macos",
3104+ "arm64"
3105+ ],
3106+ "os": "macos",
3107+ "arch": "arm64",
3108+ "version": "0.2.0",
3109+ "ephemeral": false,
3110+ "status": "online",
3111+ "work": null,
3112+ "last_seen_at": "2026-10-06T14:05:40.512Z",
3113+ "created_at": "2026-10-02T09:30:00.000Z",
3114+ "created_by": null
3115+ }
3116+ ]
3117+ },
3118+ "create_runner_registration_token": {
3119+ "response": {
3120+ "token": "g1trt_…",
3121+ "expires_at": "2026-10-06T15:04:00.000Z",
3122+ "workspace": "flagon-io",
3123+ "repo": "flagon-io/hello",
3124+ "group": null,
3125+ "url": "https://g1t.sh"
3126+ },
3127+ "notes": "Pass it to `g1t-runner register --url https://g1t.sh --token …` within the hour. See [self-hosted runners](/guides/self-hosted-runners/)."
3128+ },
3129+ "create_runner_registration_token_for_workspace": {
3130+ "params": {
3131+ "workspace": "flagon-io"
3132+ },
3133+ "request": {
3134+ "group": "Default"
3135+ },
3136+ "response": {
3137+ "token": "g1trt_…",
3138+ "expires_at": "2026-10-06T15:04:00.000Z",
3139+ "workspace": "flagon-io",
3140+ "repo": null,
3141+ "group": "Default",
3142+ "url": "https://g1t.sh"
3143+ }
3144+ },
3145+ "remove_runner": {
3146+ "params": {
3147+ "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z"
3148+ },
3149+ "response": true
3150+ },
3151+ "remove_runner_for_workspace": {
3152+ "params": {
3153+ "workspace": "flagon-io",
3154+ "id": "rnr_01kq2m8v4c7f0h3k6n9q2t5w8z"
3155+ },
3156+ "response": true
3157+ },
3158+ "get_runner_settings": {
3159+ "response": {
3160+ "agents_on_self_hosted": false,
3161+ "agent_labels": [
3162+ "self-hosted",
3163+ "linux"
3164+ ],
3165+ "fork_pull_requests": false,
3166+ "inherited": true
3167+ }
3168+ },
3169+ "get_runner_settings_for_workspace": {
3170+ "params": {
3171+ "workspace": "flagon-io"
3172+ },
3173+ "response": {
3174+ "agents_on_self_hosted": true,
3175+ "agent_labels": [
3176+ "self-hosted",
3177+ "linux"
3178+ ],
3179+ "fork_pull_requests": false,
3180+ "inherited": false
3181+ }
3182+ },
3183+ "update_runner_settings": {
3184+ "request": {
3185+ "inherit": true
3186+ },
3187+ "response": {
3188+ "agents_on_self_hosted": false,
3189+ "agent_labels": [
3190+ "self-hosted",
3191+ "linux"
3192+ ],
3193+ "fork_pull_requests": false,
3194+ "inherited": true
3195+ }
3196+ },
3197+ "update_runner_settings_for_workspace": {
3198+ "params": {
3199+ "workspace": "flagon-io"
3200+ },
3201+ "request": {
3202+ "agents_on_self_hosted": true,
3203+ "agent_labels": [
3204+ "linux"
3205+ ]
3206+ },
3207+ "response": {
3208+ "agents_on_self_hosted": true,
3209+ "agent_labels": [
3210+ "self-hosted",
3211+ "linux"
3212+ ],
3213+ "fork_pull_requests": false,
3214+ "inherited": false
3215+ },
3216+ "notes": "Agent work on your runners still uses g1t's model proxy, paid as before, unless the workspace has its own model provider."
3217+ },
3218+ "list_runner_groups": {
3219+ "params": {
3220+ "workspace": "flagon-io"
3221+ },
3222+ "response": [
3223+ {
3224+ "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6y",
3225+ "name": "Default",
3226+ "default": true,
3227+ "repositories": [],
3228+ "runners": 2,
3229+ "updated_at": "2026-10-02T09:30:00.000Z"
3230+ },
3231+ {
3232+ "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z",
3233+ "name": "GPU",
3234+ "default": false,
3235+ "repositories": [
3236+ "hello",
3237+ "models"
3238+ ],
3239+ "runners": 1,
3240+ "updated_at": "2026-10-05T11:20:00.000Z"
3241+ }
3242+ ]
3243+ },
3244+ "create_runner_group": {
3245+ "params": {
3246+ "workspace": "flagon-io"
3247+ },
3248+ "request": {
3249+ "name": "GPU",
3250+ "repositories": [
3251+ "hello",
3252+ "models"
3253+ ]
3254+ },
3255+ "response": {
3256+ "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z",
3257+ "name": "GPU",
3258+ "default": false,
3259+ "repositories": [
3260+ "hello",
3261+ "models"
3262+ ],
3263+ "runners": 1,
3264+ "updated_at": "2026-10-05T11:20:00.000Z"
3265+ }
3266+ },
3267+ "update_runner_group": {
3268+ "params": {
3269+ "workspace": "flagon-io",
3270+ "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z"
3271+ },
3272+ "request": {
3273+ "repositories": []
3274+ },
3275+ "response": {
3276+ "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z",
3277+ "name": "GPU",
3278+ "default": false,
3279+ "repositories": [],
3280+ "runners": 1,
3281+ "updated_at": "2026-10-05T11:20:00.000Z"
3282+ }
3283+ },
3284+ "delete_runner_group": {
3285+ "params": {
3286+ "workspace": "flagon-io",
3287+ "id": "rng_01kq2m7r2a5d8g1j4m7p0s3v6z"
3288+ },
3289+ "response": true
3290+ },
3291+ "list_webhooks": {
3292+ "response": [
3293+ {
3294+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3295+ "scope": "repo",
3296+ "workspace": "flagon-io",
3297+ "repo": "flagon-io/hello",
3298+ "url": "https://hooks.example.com/g1t",
3299+ "events": [
3300+ "git.push",
3301+ "pull.merged"
3302+ ],
3303+ "active": true,
3304+ "secret_hint": "…9c2e",
3305+ "created_by": "syntaqx",
3306+ "created_at": "2026-10-04T15:42:07.318Z",
3307+ "last_status": "delivered",
3308+ "last_delivered_at": "2026-10-04T15:42:07.611Z"
3309+ }
3310+ ]
3311+ },
3312+ "list_webhooks_for_workspace": {
3313+ "params": {
3314+ "workspace": "flagon-io"
3315+ },
3316+ "response": [
3317+ {
3318+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3319+ "scope": "workspace",
3320+ "workspace": "flagon-io",
3321+ "repo": null,
3322+ "url": "https://hooks.example.com/g1t",
3323+ "events": [
3324+ "git.push",
3325+ "pull.merged"
3326+ ],
3327+ "active": true,
3328+ "secret_hint": "…9c2e",
3329+ "created_by": "syntaqx",
3330+ "created_at": "2026-10-04T15:42:07.318Z",
3331+ "last_status": "delivered",
3332+ "last_delivered_at": "2026-10-04T15:42:07.611Z"
3333+ }
3334+ ]
3335+ },
3336+ "create_webhook": {
3337+ "request": {
3338+ "url": "https://hooks.example.com/g1t",
3339+ "events": [
3340+ "git.push",
3341+ "pull.merged"
3342+ ]
3343+ },
3344+ "response": {
3345+ "hook": {
3346+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3347+ "scope": "repo",
3348+ "workspace": "flagon-io",
3349+ "repo": "flagon-io/hello",
3350+ "url": "https://hooks.example.com/g1t",
3351+ "events": [
3352+ "git.push",
3353+ "pull.merged"
3354+ ],
3355+ "active": true,
3356+ "secret_hint": "…9c2e",
3357+ "created_by": "syntaqx",
3358+ "created_at": "2026-10-04T15:42:07.318Z",
3359+ "last_status": "delivered",
3360+ "last_delivered_at": "2026-10-04T15:42:07.611Z"
3361+ },
3362+ "secret": "whsec_…"
3363+ },
3364+ "notes": "A ping is sent before the response, so `last_status` is usually set already. When g1t made the signing secret, `secret` holds it: it is shown only this once. See [webhooks](/guides/webhooks/)."
3365+ },
3366+ "create_webhook_for_workspace": {
3367+ "params": {
3368+ "workspace": "flagon-io"
3369+ },
3370+ "request": {
3371+ "url": "https://hooks.example.com/g1t"
3372+ },
3373+ "response": {
3374+ "hook": {
3375+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3376+ "scope": "workspace",
3377+ "workspace": "flagon-io",
3378+ "repo": null,
3379+ "url": "https://hooks.example.com/g1t",
3380+ "events": [
3381+ "*"
3382+ ],
3383+ "active": true,
3384+ "secret_hint": "…9c2e",
3385+ "created_by": "syntaqx",
3386+ "created_at": "2026-10-04T15:42:07.318Z",
3387+ "last_status": "delivered",
3388+ "last_delivered_at": "2026-10-04T15:42:07.611Z"
3389+ },
3390+ "secret": "whsec_…"
3391+ },
3392+ "notes": "A ping is sent before the response, so `last_status` is usually set already. When g1t made the signing secret, `secret` holds it: it is shown only this once. See [webhooks](/guides/webhooks/)."
3393+ },
3394+ "update_webhook": {
3395+ "params": {
3396+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3397+ },
3398+ "request": {
3399+ "active": false
3400+ },
3401+ "response": {
3402+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3403+ "scope": "repo",
3404+ "workspace": "flagon-io",
3405+ "repo": "flagon-io/hello",
3406+ "url": "https://hooks.example.com/g1t",
3407+ "events": [
3408+ "git.push",
3409+ "pull.merged"
3410+ ],
3411+ "active": false,
3412+ "secret_hint": "…9c2e",
3413+ "created_by": "syntaqx",
3414+ "created_at": "2026-10-04T15:42:07.318Z",
3415+ "last_status": "delivered",
3416+ "last_delivered_at": "2026-10-04T15:42:07.611Z"
3417+ }
3418+ },
3419+ "update_webhook_for_workspace": {
3420+ "params": {
3421+ "workspace": "flagon-io",
3422+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3423+ },
3424+ "request": {
3425+ "active": false
3426+ },
3427+ "response": {
3428+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3429+ "scope": "workspace",
3430+ "workspace": "flagon-io",
3431+ "repo": null,
3432+ "url": "https://hooks.example.com/g1t",
3433+ "events": [
3434+ "git.push",
3435+ "pull.merged"
3436+ ],
3437+ "active": false,
3438+ "secret_hint": "…9c2e",
3439+ "created_by": "syntaqx",
3440+ "created_at": "2026-10-04T15:42:07.318Z",
3441+ "last_status": "delivered",
3442+ "last_delivered_at": "2026-10-04T15:42:07.611Z"
3443+ }
3444+ },
3445+ "delete_webhook": {
3446+ "params": {
3447+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3448+ },
3449+ "response": true
3450+ },
3451+ "delete_webhook_for_workspace": {
3452+ "params": {
3453+ "workspace": "flagon-io",
3454+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3455+ },
3456+ "response": true
3457+ },
3458+ "ping_webhook": {
3459+ "params": {
3460+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3461+ },
3462+ "response": {
3463+ "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3464+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3465+ "event_id": "",
3466+ "event": "ping",
3467+ "status": "delivered",
3468+ "attempts": 1,
3469+ "response_status": 200,
3470+ "response_body": "ok",
3471+ "error": null,
3472+ "duration_ms": 184,
3473+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3474+ "created_at": "2026-10-04T16:01:12.440Z",
3475+ "delivered_at": "2026-10-04T16:01:12.631Z",
3476+ "next_attempt_at": null
3477+ },
3478+ "notes": "`payload` is the JSON that was sent, as a string."
3479+ },
3480+ "ping_webhook_for_workspace": {
3481+ "params": {
3482+ "workspace": "flagon-io",
3483+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3484+ },
3485+ "response": {
3486+ "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3487+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3488+ "event_id": "",
3489+ "event": "ping",
3490+ "status": "delivered",
3491+ "attempts": 1,
3492+ "response_status": 200,
3493+ "response_body": "ok",
3494+ "error": null,
3495+ "duration_ms": 184,
3496+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3497+ "created_at": "2026-10-04T16:01:12.440Z",
3498+ "delivered_at": "2026-10-04T16:01:12.631Z",
3499+ "next_attempt_at": null
3500+ }
3501+ },
3502+ "list_webhook_deliveries": {
3503+ "params": {
3504+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3505+ },
3506+ "response": [
3507+ {
3508+ "id": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz",
3509+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3510+ "event_id": "",
3511+ "event": "ping",
3512+ "status": "pending",
3513+ "attempts": 1,
3514+ "response_status": 503,
3515+ "response_body": "Service Unavailable",
3516+ "error": null,
3517+ "duration_ms": 212,
3518+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3519+ "created_at": "2026-10-04T16:20:03.100Z",
3520+ "delivered_at": null,
3521+ "next_attempt_at": "2026-10-04T16:21:03.312Z"
3522+ },
3523+ {
3524+ "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3525+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3526+ "event_id": "",
3527+ "event": "ping",
3528+ "status": "delivered",
3529+ "attempts": 1,
3530+ "response_status": 200,
3531+ "response_body": "ok",
3532+ "error": null,
3533+ "duration_ms": 184,
3534+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3535+ "created_at": "2026-10-04T16:01:12.440Z",
3536+ "delivered_at": "2026-10-04T16:01:12.631Z",
3537+ "next_attempt_at": null
3538+ }
3539+ ],
3540+ "notes": "Returns at most 50, newest first. `status` is `pending`, `delivered` or `failed`; `next_attempt_at` is set while it is pending."
3541+ },
3542+ "list_webhook_deliveries_for_workspace": {
3543+ "params": {
3544+ "workspace": "flagon-io",
3545+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd"
3546+ },
3547+ "response": [
3548+ {
3549+ "id": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz",
3550+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3551+ "event_id": "",
3552+ "event": "ping",
3553+ "status": "pending",
3554+ "attempts": 1,
3555+ "response_status": 503,
3556+ "response_body": "Service Unavailable",
3557+ "error": null,
3558+ "duration_ms": 212,
3559+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3560+ "created_at": "2026-10-04T16:20:03.100Z",
3561+ "delivered_at": null,
3562+ "next_attempt_at": "2026-10-04T16:21:03.312Z"
3563+ },
3564+ {
3565+ "id": "dlv_01kpx5p9v2j7k3m8n4p5q6r7st",
3566+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3567+ "event_id": "",
3568+ "event": "ping",
3569+ "status": "delivered",
3570+ "attempts": 1,
3571+ "response_status": 200,
3572+ "response_body": "ok",
3573+ "error": null,
3574+ "duration_ms": 184,
3575+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3576+ "created_at": "2026-10-04T16:01:12.440Z",
3577+ "delivered_at": "2026-10-04T16:01:12.631Z",
3578+ "next_attempt_at": null
3579+ }
3580+ ]
3581+ },
3582+ "redeliver_webhook": {
3583+ "params": {
3584+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3585+ "delivery": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz"
3586+ },
3587+ "response": {
3588+ "id": "dlv_01kpx6c8d1e2f3g4h5j6k7m8np",
3589+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3590+ "event_id": "",
3591+ "event": "ping",
3592+ "status": "delivered",
3593+ "attempts": 1,
3594+ "response_status": 200,
3595+ "response_body": "ok",
3596+ "error": null,
3597+ "duration_ms": 171,
3598+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3599+ "created_at": "2026-10-04T16:25:40.007Z",
3600+ "delivered_at": "2026-10-04T16:25:40.178Z",
3601+ "next_attempt_at": null
3602+ },
3603+ "notes": "The response is the new delivery."
3604+ },
3605+ "redeliver_webhook_for_workspace": {
3606+ "params": {
3607+ "workspace": "flagon-io",
3608+ "id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3609+ "delivery": "dlv_01kpx6a2b3c4d5e6f7g8h9j0kz"
3610+ },
3611+ "response": {
3612+ "id": "dlv_01kpx6c8d1e2f3g4h5j6k7m8np",
3613+ "hook_id": "hk_01kpx5p9s4h0t1w6x8y2a3b4cd",
3614+ "event_id": "",
3615+ "event": "ping",
3616+ "status": "delivered",
3617+ "attempts": 1,
3618+ "response_status": 200,
3619+ "response_body": "ok",
3620+ "error": null,
3621+ "duration_ms": 171,
3622+ "payload": "{\"hook\":{\"events\":[\"git.push\",\"pull.merged\"],\"id\":\"hk_01kpx5p9s4h0t1w6x8y2a3b4cd\",\"url\":\"https://hooks.example.com/g1t\"},\"message\":\"g1t will send this webhook's events here.\",\"time\":\"2026-10-04T16:01:12.440Z\",\"type\":\"ping\"}",
3623+ "created_at": "2026-10-04T16:25:40.007Z",
3624+ "delivered_at": "2026-10-04T16:25:40.178Z",
3625+ "next_attempt_at": null
3626+ }
3627+ },
3628+ "list_integrations": {
3629+ "params": {
3630+ "workspace": "flagon-io"
3631+ },
3632+ "response": [
3633+ {
3634+ "id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3635+ "workspace": "flagon-io",
3636+ "provider": "anthropic",
3637+ "kind": "models",
3638+ "name": "Anthropic",
3639+ "config": {
3640+ "assign": false,
3641+ "write_back": true
3642+ },
3643+ "secret_hint": "…3f9a",
3644+ "webhook_url": null,
3645+ "created_by": "syntaqx",
3646+ "created_at": "2026-10-04T15:42:07.318Z",
3647+ "last_used_at": "2026-10-04T15:42:08.102Z",
3648+ "last_error": null,
3649+ "models": [
3650+ "claude-haiku-4-5",
3651+ "claude-sonnet-4-5"
3652+ ]
3653+ },
3654+ {
3655+ "id": "con_01kpx4n8r3g9s0v5w7x1z2a3bc",
3656+ "workspace": "flagon-io",
3657+ "provider": "jira",
3658+ "kind": "tracker",
3659+ "name": "Jira",
3660+ "config": {
3661+ "assign": false,
3662+ "write_back": true,
3663+ "site": "https://acme.atlassian.net",
3664+ "email": "syntaqx@example.com",
3665+ "keys": [
3666+ "TECH"
3667+ ]
3668+ },
3669+ "secret_hint": "…x7Qe",
3670+ "webhook_url": null,
3671+ "created_by": "syntaqx",
3672+ "created_at": "2026-10-04T15:42:07.318Z",
3673+ "last_used_at": null,
3674+ "last_error": null,
3675+ "models": []
3676+ }
3677+ ],
3678+ "notes": "`kind` is `models`, `alerts` or `tracker`. `secret_hint` shows the end of the secret; the secret itself is never returned. `webhook_url` is where an alert source sends its alerts."
3679+ },
3680+ "connect_integration": {
3681+ "params": {
3682+ "workspace": "flagon-io"
3683+ },
3684+ "request": {
3685+ "provider": "webhook",
3686+ "config": {
3687+ "repo": "flagon-io/hello",
3688+ "label": "bug"
3689+ }
3690+ },
3691+ "response": {
3692+ "connection": {
3693+ "id": "con_01kpx4n8r3g9s0v5w7x1z2a3bd",
3694+ "workspace": "flagon-io",
3695+ "provider": "webhook",
3696+ "kind": "alerts",
3697+ "name": "Webhook",
3698+ "config": {
3699+ "repo": "flagon-io/hello",
3700+ "label": "bug",
3701+ "assign": false,
3702+ "write_back": true
3703+ },
3704+ "secret_hint": null,
3705+ "webhook_url": "https://api.g1t.sh/hooks/con_01kpx4n8r3g9s0v5w7x1z2a3bd",
3706+ "created_by": "syntaqx",
3707+ "created_at": "2026-10-04T15:42:07.318Z",
3708+ "last_used_at": null,
3709+ "last_error": null,
3710+ "models": []
3711+ },
3712+ "signing_secret": "g1ts_9f2c4a7e1b0d3c6f8a2e5b7d9c1f4a6e8b0d2c4f6a8e1b3d"
3713+ },
3714+ "notes": "`signing_secret` is set only when g1t made it, for `datadog` and `webhook`, and is shown only this once. A model provider is tested as it is connected. See [integrations](/guides/integrations/) and [model providers](/guides/models/)."
3715+ },
3716+ "disconnect_integration": {
3717+ "params": {
3718+ "workspace": "flagon-io",
3719+ "id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab"
3720+ },
3721+ "response": true
3722+ },
3723+ "test_integration": {
3724+ "params": {
3725+ "workspace": "flagon-io",
3726+ "id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab"
3727+ },
3728+ "response": {
3729+ "ok": true,
3730+ "message": "Anthropic accepted the key and offers 9 models."
3731+ },
3732+ "notes": "Credentials that do not work still answer `200`, with `ok` false and `message` saying what went wrong."
3733+ },
3734+ "get_model_routes": {
3735+ "params": {
3736+ "workspace": "flagon-io"
3737+ },
3738+ "response": [
3739+ {
3740+ "task": "default",
3741+ "connection_id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3742+ "model": "claude-sonnet-4-5"
3743+ },
3744+ {
3745+ "task": "review",
3746+ "connection_id": null,
3747+ "model": null
3748+ }
3749+ ]
3750+ },
3751+ "set_model_routes": {
3752+ "params": {
3753+ "workspace": "flagon-io"
3754+ },
3755+ "request": {
3756+ "routes": [
3757+ {
3758+ "task": "default",
3759+ "connection_id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3760+ "model": "claude-sonnet-4-5"
3761+ },
3762+ {
3763+ "task": "plan",
3764+ "connection_id": null,
3765+ "model": "frontier"
3766+ },
3767+ {
3768+ "task": "review",
3769+ "connection_id": null
3770+ }
3771+ ]
3772+ },
3773+ "response": [
3774+ {
3775+ "task": "default",
3776+ "connection_id": "con_01kpx3m7q2f8r9t4v6w0y1z2ab",
3777+ "model": "claude-sonnet-4-5"
3778+ },
3779+ {
3780+ "task": "plan",
3781+ "connection_id": null,
3782+ "model": "frontier"
3783+ },
3784+ {
3785+ "task": "review",
3786+ "connection_id": null,
3787+ "model": null
3788+ }
3789+ ],
3790+ "notes": "The response is the routes as saved, ordered by task. On g1t's hosted models (`connection_id` null), `model` is `small`, `large` or `frontier`, or null for Auto, which picks the cheapest model that can do each job and says why on the run."
3791+ },
3792+ "get_context": {
3793+ "query": {
3794+ "reference": "TECH-1234"
3795+ },
3796+ "response": {
3797+ "provider": "jira",
3798+ "key": "TECH-1234",
3799+ "title": "Checkout fails for EU cards",
3800+ "url": "https://acme.atlassian.net/browse/TECH-1234",
3801+ "status": "In Progress",
3802+ "body": "Customers with 3DS cards see a 500 at /pay.",
3803+ "fetched_at": "2026-10-04T15:42:07.318Z"
3804+ }
3805+ },
3806+ "import_issue": {
3807+ "request": {
3808+ "reference": "TECH-1234"
3809+ },
3810+ "response": {
3811+ "number": 42,
3812+ "item": {
3813+ "provider": "jira",
3814+ "key": "TECH-1234",
3815+ "title": "Checkout fails for EU cards",
3816+ "url": "https://acme.atlassian.net/browse/TECH-1234",
3817+ "status": "In Progress",
3818+ "body": "Customers with 3DS cards see a 500 at /pay.",
3819+ "fetched_at": "2026-10-04T15:42:07.318Z"
3820+ },
3821+ "created": true
3822+ },
3823+ "notes": "`created` is false when the ticket was imported before; `number` is then that issue."
3824+ },
3825+ "remember": {
3826+ "request": {
3827+ "text": "The tests need TZ=UTC or the date tests fail.",
3828+ "scope": "project",
3829+ "kind": "gotcha",
3830+ "from_number": 14
3831+ },
3832+ "response": {
3833+ "id": "mem_01m43v8q2w3e4r5t6y7u8i9o0p",
3834+ "scope": "project",
3835+ "workspace": "flagon-io",
3836+ "repo": {
3837+ "namespace": "flagon-io",
3838+ "name": "hello"
3839+ },
3840+ "text": "The tests need TZ=UTC or the date tests fail.",
3841+ "kind": "gotcha",
3842+ "source": {
3843+ "kind": "run",
3844+ "run_id": "arn_01m43v2c1p9k8d7e6f5a4b3c2d",
3845+ "repo": {
3846+ "namespace": "flagon-io",
3847+ "name": "hello"
3848+ },
3849+ "number": 14
3850+ },
3851+ "created_by": "g1t",
3852+ "pinned": false,
3853+ "created_at": "2026-10-01T18:40:12.000Z",
3854+ "updated_at": "2026-10-01T18:40:12.000Z",
3855+ "last_used_at": null
3856+ },
3857+ "notes": "Text that looks like a key, a token or a password is refused with `invalid`: memory is read by every agent in the workspace. Saving the same text again in the same scope returns the memory already kept."
3858+ },
3859+ "recall": {
3860+ "query": {
3861+ "q": "pnpm"
3862+ },
3863+ "response": {
3864+ "project": [],
3865+ "workspace": [
3866+ {
3867+ "id": "mem_01m43t0a1s2d3f4g5h6j7k8l9z",
3868+ "scope": "workspace",
3869+ "workspace": "flagon-io",
3870+ "repo": null,
3871+ "text": "We use pnpm everywhere, never npm or yarn.",
3872+ "kind": "convention",
3873+ "source": {
3874+ "kind": "person",
3875+ "run_id": null,
3876+ "repo": null,
3877+ "number": null
3878+ },
3879+ "created_by": "syntaqx",
3880+ "pinned": true,
3881+ "created_at": "2026-10-01T18:40:12.000Z",
3882+ "updated_at": "2026-10-01T18:40:12.000Z",
3883+ "last_used_at": null
3884+ }
3885+ ]
3886+ },
3887+ "notes": "Anyone who can read the repository gets its project memory; `workspace` is filled only for members of the workspace, and is empty for anyone else. Each memory returned is marked used, which keeps it near the front of what agents are given."
3888+ },
3889+ "search": {
3890+ "query": {
3891+ "q": "parse_query language:rust repo:acme/web",
3892+ "type": "code"
3893+ },
3894+ "response": {
3895+ "query": "parse_query repo:acme/web language:rust",
3896+ "type": "code",
3897+ "counts": {
3898+ "repositories": 0,
3899+ "code": 2,
3900+ "issues": 0,
3901+ "pulls": 0,
3902+ "people": 0
3903+ },
3904+ "page": 1,
3905+ "per_page": 20,
3906+ "more": false,
3907+ "hits": [
3908+ {
3909+ "kind": "code",
3910+ "title": "src/search/query.rs",
3911+ "url": "/acme/web/blob/main/src/search/query.rs#L42",
3912+ "repo": "acme/web",
3913+ "private": false,
3914+ "description": null,
3915+ "snippet": [],
3916+ "lines": [
3917+ {
3918+ "number": 41,
3919+ "parts": [
3920+ {
3921+ "text": "/// Reads a query typed into the search box.",
3922+ "highlight": false
3923+ }
3924+ ]
3925+ },
3926+ {
3927+ "number": 42,
3928+ "parts": [
3929+ {
3930+ "text": "pub fn ",
3931+ "highlight": false
3932+ },
3933+ {
3934+ "text": "parse_query",
3935+ "highlight": true
3936+ },
3937+ {
3938+ "text": "(text: &str) -> Query {",
3939+ "highlight": false
3940+ }
3941+ ]
3942+ },
3943+ {
3944+ "number": 43,
3945+ "parts": [
3946+ {
3947+ "text": " let mut query = Query::default();",
3948+ "highlight": false
3949+ }
3950+ ]
3951+ }
3952+ ],
3953+ "path": "src/search/query.rs",
3954+ "language": "rust",
3955+ "ref": "main",
3956+ "number": null,
3957+ "state": null,
3958+ "author": null,
3959+ "requested_by": null,
3960+ "labels": [],
3961+ "topics": [],
3962+ "slug": null,
3963+ "avatar": null,
3964+ "updated_at": null
3965+ }
3966+ ],
3967+ "notes": []
3968+ },
3969+ "notes": "`q` takes words, `\"exact phrases\"`, `-words` to leave out, and qualifiers: `repo:owner/name`, `org:` (or `workspace:`), `language:`, `path:` (a glob when it has `*`), `is:issue`, `is:pr`, `is:open`, `is:closed`, `is:merged`, `is:draft`, `is:public`, `is:private`, `author:` and `label:`; most can be left out with a leading `-`, as in `-label:wontfix`. `type` is `repositories`, `code`, `issues`, `pulls` or `people`; without it, `path:` means code, `is:pr` pull requests, `is:open`, `author:` or `label:` issues, and anything else repositories. `counts` says how many results each type has, up to 1,000. Each result's `snippet` (or, for code, each of its `lines`) is a list of parts, `highlight` true where the query matched. Code is searched on default branches and needs a word of three characters or more, unless the query names a `repo:`. Public content is returned to anyone, without a token; private content only to people who can read it (members of its workspace, and people given a role on the repository), checked when the search runs, so a repository made private, or a role taken away, stops appearing at once. A g1t agent's token can search too. An issue or pull request g1t opened has `author` `g1t` and `requested_by` the person it was for; `author:` matches the author."
3970+ },
3971+ "search_context": {
3972+ "params": {
3973+ "workspace": "acme"
3974+ },
3975+ "query": {
3976+ "q": "how do we run the web tests",
3977+ "project": "web"
3978+ },
3979+ "response": {
3980+ "query": "how do we run the web tests",
3981+ "mode": "semantic",
3982+ "hits": [
3983+ {
3984+ "kind": "memory",
3985+ "id": "mem_01m4a0c2b7k3f9d1e5g8h2j6k4",
3986+ "title": "Gotcha",
3987+ "snippet": "The date tests fail unless TZ=UTC.",
3988+ "project": "web",
3989+ "url": "/acme/web/memory",
3990+ "score": 0.82,
3991+ "source": "AGENTS.md",
3992+ "by": "g1t",
3993+ "updated_at": "2026-10-04T21:10:02.000Z"
3994+ },
3995+ {
3996+ "kind": "doc",
3997+ "id": "ent_5f0c2a9e41d7b3c86a1e2f40:2",
3998+ "title": "Web (README.md)",
3999+ "snippet": "## Testing Run npm test. The end-to-end tests need the api running locally…",
4000+ "project": "web",
4001+ "url": "/acme/web/blob/main/README.md",
4002+ "score": 0.77,
4003+ "source": "README.md",
4004+ "by": null,
4005+ "updated_at": "2026-10-04T20:58:41.000Z"
4006+ },
4007+ {
4008+ "kind": "project",
4009+ "id": "ent_9b1d6f0a2c3e4b5d6e7f8a9b",
4010+ "title": "web",
4011+ "snippet": "The storefront. Written in TypeScript. Packages: @acme/web. Uses api. Owned by ana.",
4012+ "project": "web",
4013+ "url": "/acme/web",
4014+ "score": 0.71,
4015+ "source": "catalog",
4016+ "by": null,
4017+ "updated_at": "2026-10-04T20:58:41.000Z"
4018+ }
4019+ ]
4020+ },
4021+ "notes": "Give `workspace`, or `repo` as `owner/name` for its workspace. `kinds` narrows to some of `project`, `app`, `api`, `package`, `language`, `owner`, `environment`, `integration`, `doc`, `memory`, `issue` and `pull`; in a URL, comma-separated. `mode` is `text` when the search index could not answer and words were matched instead. Memory is returned only to members of the workspace and its agents; anything from a private project, only to those who can read it (members, unless the base permission is None, and people given a role on its repository). A g1t agent searches its own workspace only."
4022+ },
4023+ "get_entity": {
4024+ "params": {
4025+ "workspace": "acme",
4026+ "kind": "project",
4027+ "id": "web"
4028+ },
4029+ "response": {
4030+ "entity": {
4031+ "id": "ent_9b1d6f0a2c3e4b5d6e7f8a9b",
4032+ "workspace": "acme",
4033+ "kind": "project",
4034+ "key": "web",
4035+ "name": "web",
4036+ "summary": "The storefront. Written in TypeScript. Packages: @acme/web. Uses api. Owned by ana.",
4037+ "project": "web",
4038+ "private": true,
4039+ "data": {
4040+ "repo": "acme/web",
4041+ "root_dir": "",
4042+ "default_branch": "main",
4043+ "languages": [
4044+ "TypeScript"
4045+ ],
4046+ "owners": [
4047+ "ana"
4048+ ],
4049+ "tests": true,
4050+ "test_commands": [
4051+ "npm test"
4052+ ],
4053+ "production_url": "https://web--acme.g1t.page"
4054+ },
4055+ "source": "scan",
4056+ "ref": "/acme/web",
4057+ "updated_at": "2026-10-04T20:58:41.000Z"
4058+ },
4059+ "relations": [
4060+ {
4061+ "kind": "depends_on",
4062+ "direction": "out",
4063+ "entity": {
4064+ "id": "ent_0a7c3e5b9d1f2a4c6e8b0d2f",
4065+ "workspace": "acme",
4066+ "kind": "project",
4067+ "key": "api",
4068+ "name": "api",
4069+ "summary": "The public API. Written in Rust.",
4070+ "project": "api",
4071+ "private": true,
4072+ "data": {},
4073+ "source": "scan",
4074+ "ref": "/acme/api",
4075+ "updated_at": "2026-10-04T20:57:12.000Z"
4076+ }
4077+ },
4078+ {
4079+ "kind": "owned_by",
4080+ "direction": "out",
4081+ "entity": {
4082+ "id": "ent_3c5e7a9b1d2f4a6c8e0b2d4f",
4083+ "workspace": "acme",
4084+ "kind": "owner",
4085+ "key": "ana",
4086+ "name": "ana",
4087+ "summary": null,
4088+ "project": null,
4089+ "private": false,
4090+ "data": {},
4091+ "source": "scan",
4092+ "ref": "/u/ana",
4093+ "updated_at": "2026-10-04T20:58:41.000Z"
4094+ }
4095+ }
4096+ ]
4097+ },
4098+ "notes": "`id` is the entry's id, or its key: a project's or app's slug, `npm:<name>` (or `cargo:`, `go:`, `pypi:`) for a package, a username for an owner, `<project>/production` for an environment. `data` depends on the kind: a package's version and dependencies, an API's routes, an app's production address."
4099+ },
4100+ "list_collaborators": {
4101+ "response": {
4102+ "repo": "flagon-io/hello",
4103+ "base_permission": "write",
4104+ "people": [
4105+ {
4106+ "username": "syntaqx",
4107+ "name": "Chase Pierce",
4108+ "avatar": null,
4109+ "role": "admin",
4110+ "source": "owner",
4111+ "direct": null,
4112+ "workspace_role": "owner"
4113+ },
4114+ {
4115+ "username": "linus",
4116+ "name": null,
4117+ "avatar": null,
4118+ "role": "maintain",
4119+ "source": "direct",
4120+ "direct": "maintain",
4121+ "workspace_role": "member"
4122+ },
4123+ {
4124+ "username": "grace",
4125+ "name": "Grace Hopper",
4126+ "avatar": null,
4127+ "role": "write",
4128+ "source": "base",
4129+ "direct": null,
4130+ "workspace_role": "member"
4131+ },
4132+ {
4133+ "username": "ada",
4134+ "name": "Ada Lovelace",
4135+ "avatar": null,
4136+ "role": "triage",
4137+ "source": "direct",
4138+ "direct": "triage",
4139+ "workspace_role": null
4140+ }
4141+ ],
4142+ "invitations": [
4143+ {
4144+ "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p",
4145+ "repo": "flagon-io/hello",
4146+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4147+ "invitee": "alan",
4148+ "email": null,
4149+ "role": "write",
4150+ "invited_by": "syntaqx",
4151+ "inviter_avatar": null,
4152+ "status": "pending",
4153+ "created_at": "2026-10-05T17:00:00.000Z",
4154+ "expires_at": "2026-10-12T17:00:00.000Z"
4155+ },
4156+ {
4157+ "id": "rin_01kp3d7e8f9g0h1j2k3m4n5p6q",
4158+ "repo": "flagon-io/hello",
4159+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4160+ "invitee": null,
4161+ "email": "joan@example.com",
4162+ "role": "read",
4163+ "invited_by": "syntaqx",
4164+ "inviter_avatar": null,
4165+ "status": "pending",
4166+ "created_at": "2026-10-05T17:00:00.000Z",
4167+ "expires_at": "2026-10-12T17:00:00.000Z"
4168+ }
4169+ ],
4170+ "viewer_role": "admin",
4171+ "can_manage": true
4172+ },
4173+ "notes": "Owners are listed with `source` `owner`, members with the base permission with `base`, and anyone given a role on this repository with `direct`; `role` is the highest of these, and `direct` shows a direct role even when ownership or the base permission gives more. `workspace_role` null means an outside collaborator. Anyone can read a public repository, which is not listed. `invitations` is empty unless you have the Admin role (`can_manage`). Refused with `403` below the Write role, and `404` for a private repository you cannot see. See [Access and roles](/guides/access-and-roles/)."
4174+ },
4175+ "add_collaborator": {
4176+ "request": {
4177+ "invitee": "ada",
4178+ "role": "triage"
4179+ },
4180+ "response": {
4181+ "result": "invited",
4182+ "invitation": {
4183+ "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4184+ "repo": "flagon-io/hello",
4185+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4186+ "invitee": "ada",
4187+ "email": null,
4188+ "role": "triage",
4189+ "invited_by": "syntaqx",
4190+ "inviter_avatar": null,
4191+ "status": "pending",
4192+ "created_at": "2026-10-05T17:00:00.000Z",
4193+ "expires_at": "2026-10-12T17:00:00.000Z"
4194+ }
4195+ },
4196+ "notes": "`invitee` is a username or an email address. A member of the workspace answers `{\"result\": \"granted\", \"collaborator\": {…}}` with the role already given, shown as list_collaborators shows a person. Anyone else answers `{\"result\": \"invited\", \"invitation\": {…}}`: the invitation is emailed and waits 7 days, and the role is theirs once they accept it. An email address without an account gets an invitation with `email` set and `invitee` null, and an invite that makes the account and accepts in one step. Refused with `404` when no account has that username, `409` when they already have a role of their own or a pending invitation (change it with update_collaborator), and `403` without the Admin role, from an agent's or a workspace's token, or when the person does not meet what the workspace asks of everyone with access. collaborator_added` webhook event is sent once they have the role. See [Access and roles](/guides/access-and-roles/). On a free workspace, inviting anyone who is not a member answers `402` with `payment_required` until it starts the g1t plan."
4197+ },
4198+ "update_collaborator": {
4199+ "params": {
4200+ "owner": "flagon-io",
4201+ "name": "hello",
4202+ "username": "ada"
4203+ },
4204+ "request": {
4205+ "role": "write"
4206+ },
4207+ "response": {
4208+ "username": "ada",
4209+ "name": "Ada Lovelace",
4210+ "avatar": null,
4211+ "role": "write",
4212+ "source": "direct",
4213+ "direct": "write",
4214+ "workspace_role": null
4215+ },
4216+ "notes": "Changes a direct role, or the role of the person's pending invitation. `404` when they have neither: an owner's Admin and a member's base permission are not changed here. Changing a direct role sends the `repo.collaborator_role_changed` webhook event. See [Access and roles](/guides/access-and-roles/)."
4217+ },
4218+ "remove_collaborator": {
4219+ "params": {
4220+ "owner": "flagon-io",
4221+ "name": "hello",
4222+ "username": "ada"
4223+ },
4224+ "response": true,
4225+ "notes": "Takes away a direct role. Anyone may remove their own, to leave a repository. `404` when the person has no role of their own on it. A member keeps the workspace's base permission. Sends the `repo.collaborator_removed` webhook event. See [Access and roles](/guides/access-and-roles/)."
4226+ },
4227+ "get_collaborator_permission": {
4228+ "params": {
4229+ "owner": "flagon-io",
4230+ "name": "hello",
4231+ "username": "ada"
4232+ },
4233+ "response": {
4234+ "username": "ada",
4235+ "role": "triage",
4236+ "source": "direct",
4237+ "capabilities": [
4238+ "read",
4239+ "participate",
4240+ "triage"
4241+ ]
4242+ },
4243+ "notes": "`capabilities` lists what the role allows, in the table's order: `read`, `participate`, `triage`, `push`, `merge`, `run`, `manage_settings`, `manage_protection`, `manage_integrations`, `manage_access`, `administer` and `delete` (which also takes an owner of the workspace). `role` and `source` are null, and `capabilities` empty, for someone with no role. Refused with `403` below the Write role, unless you ask about yourself. See [Access and roles](/guides/access-and-roles/)."
4244+ },
4245+ "list_repo_invitations": {
4246+ "response": [
4247+ {
4248+ "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p",
4249+ "repo": "flagon-io/hello",
4250+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4251+ "invitee": "alan",
4252+ "email": null,
4253+ "role": "write",
4254+ "invited_by": "syntaqx",
4255+ "inviter_avatar": null,
4256+ "status": "pending",
4257+ "created_at": "2026-10-05T17:00:00.000Z",
4258+ "expires_at": "2026-10-12T17:00:00.000Z"
4259+ },
4260+ {
4261+ "id": "rin_01kp3d7e8f9g0h1j2k3m4n5p6q",
4262+ "repo": "flagon-io/hello",
4263+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4264+ "invitee": null,
4265+ "email": "joan@example.com",
4266+ "role": "read",
4267+ "invited_by": "syntaqx",
4268+ "inviter_avatar": null,
4269+ "status": "pending",
4270+ "created_at": "2026-10-05T17:00:00.000Z",
4271+ "expires_at": "2026-10-12T17:00:00.000Z"
4272+ }
4273+ ],
4274+ "notes": "Pending invitations only, newest first. `email` is set for an invitation sent to an address that had no account. Refused with `403` without the Admin role. See [Access and roles](/guides/access-and-roles/)."
4275+ },
4276+ "revoke_repo_invitation": {
4277+ "params": {
4278+ "owner": "flagon-io",
4279+ "name": "hello",
4280+ "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p"
4281+ },
4282+ "response": {
4283+ "id": "rin_01kp3c4d5e6f7g8h9j0k1m2n3p",
4284+ "repo": "flagon-io/hello",
4285+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4286+ "invitee": "alan",
4287+ "email": null,
4288+ "role": "write",
4289+ "invited_by": "syntaqx",
4290+ "inviter_avatar": null,
4291+ "status": "revoked",
4292+ "created_at": "2026-10-05T17:00:00.000Z",
4293+ "expires_at": "2026-10-12T17:00:00.000Z"
4294+ },
4295+ "notes": "`404` when there is no pending invitation with that id on this repository."
4296+ },
4297+ "list_my_repo_invitations": {
4298+ "response": [
4299+ {
4300+ "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4301+ "repo": "flagon-io/hello",
4302+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4303+ "invitee": "ada",
4304+ "email": null,
4305+ "role": "triage",
4306+ "invited_by": "syntaqx",
4307+ "inviter_avatar": null,
4308+ "status": "pending",
4309+ "created_at": "2026-10-05T17:00:00.000Z",
4310+ "expires_at": "2026-10-12T17:00:00.000Z"
4311+ }
4312+ ],
4313+ "notes": "Invitations sent to your username, and to any of your confirmed addresses before you had an account, newest first. Accept one with `PATCH /user/repository_invitations/{id}`, or decline it with `DELETE`. Expired and answered ones are left out."
4314+ },
4315+ "accept_repo_invitation": {
4316+ "params": {
4317+ "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r"
4318+ },
4319+ "response": {
4320+ "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4321+ "repo": "flagon-io/hello",
4322+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4323+ "invitee": "ada",
4324+ "email": null,
4325+ "role": "triage",
4326+ "invited_by": "syntaqx",
4327+ "inviter_avatar": null,
4328+ "status": "accepted",
4329+ "created_at": "2026-10-05T17:00:00.000Z",
4330+ "expires_at": "2026-10-12T17:00:00.000Z"
4331+ },
4332+ "notes": "The role is yours at once. `404` when you have no pending invitation with that id (it may have expired or been revoked), and `403` when your account does not meet what the workspace asks of everyone with access, such as two-factor authentication, with a message that says what to turn on. See [Access and roles](/guides/access-and-roles/)."
4333+ },
4334+ "decline_repo_invitation": {
4335+ "params": {
4336+ "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r"
4337+ },
4338+ "response": {
4339+ "id": "rin_01kp3e9f0g1h2j3k4m5n6p7q8r",
4340+ "repo": "flagon-io/hello",
4341+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4342+ "invitee": "ada",
4343+ "email": null,
4344+ "role": "triage",
4345+ "invited_by": "syntaqx",
4346+ "inviter_avatar": null,
4347+ "status": "declined",
4348+ "created_at": "2026-10-05T17:00:00.000Z",
4349+ "expires_at": "2026-10-12T17:00:00.000Z"
4350+ },
4351+ "notes": "`404` when you have no pending invitation with that id."
4352+ },
4353+ "set_base_permission": {
4354+ "params": {
4355+ "workspace": "flagon-io"
4356+ },
4357+ "request": {
4358+ "base_permission": "read"
4359+ },
4360+ "response": {
4361+ "workspace": "flagon-io",
4362+ "base_permission": "read"
4363+ },
4364+ "notes": "`base_permission` is `none`, `read`, `write` (the default) or `admin`. Owners keep Admin, and a role given on a repository directly still counts where it is higher. Refused with `403` for anyone but an owner signed in as a person. See [Access and roles](/guides/access-and-roles/)."
4365+ },
4366+ "list_outside_collaborators": {
4367+ "params": {
4368+ "workspace": "flagon-io"
4369+ },
4370+ "response": [
4371+ {
4372+ "username": "ada",
4373+ "name": "Ada Lovelace",
4374+ "avatar": null,
4375+ "repos": [
4376+ {
4377+ "repo": "flagon-io/docs",
4378+ "role": "write"
4379+ },
4380+ {
4381+ "repo": "flagon-io/hello",
4382+ "role": "triage"
4383+ }
4384+ ]
4385+ }
4386+ ],
4387+ "notes": "By username, each with the repositories they have a role on. Refused with `403` for anyone but an owner. See [Access and roles](/guides/access-and-roles/)."
4388+ },
4389+ "list_teams": {
4390+ "params": {
4391+ "workspace": "flagon-io"
4392+ },
4393+ "query": {
4394+ "q": "back"
4395+ },
4396+ "response": [
4397+ {
4398+ "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4399+ "workspace": "flagon-io",
4400+ "slug": "backend",
4401+ "name": "Backend",
4402+ "description": "The API and the services behind it.",
4403+ "visibility": "visible",
4404+ "parent": {
4405+ "slug": "engineering",
4406+ "name": "Engineering"
4407+ },
4408+ "notify": true,
4409+ "review_assignment": {
4410+ "enabled": false,
4411+ "algorithm": "round_robin",
4412+ "count": 1,
4413+ "skip_busy": false,
4414+ "busy_at": 5,
4415+ "include_child_teams": false,
4416+ "excluded": [],
4417+ "notify_team": false
4418+ },
4419+ "members_count": 4,
4420+ "repos_count": 2,
4421+ "child_teams_count": 1,
4422+ "viewer_role": "maintainer",
4423+ "can_manage": true,
4424+ "created_at": "2026-10-06T15:02:11.480Z",
4425+ "updated_at": "2026-10-06T15:02:11.480Z"
4426+ }
4427+ ],
4428+ "notes": "Teams you are in come first, then the rest by name. A secret team is listed only for its own people and the workspace's owners. `review_assignment` is what happens when the team is asked to review: see [`set_team_review_assignment`](/reference/api/teams/set-team-review-assignment/). `403` for anyone who is not a member of the workspace. See [Teams](/guides/teams/)."
4429+ },
4430+ "create_team": {
4431+ "params": {
4432+ "workspace": "flagon-io"
4433+ },
4434+ "request": {
4435+ "name": "Backend",
4436+ "description": "The API and the services behind it.",
4437+ "visibility": "visible",
4438+ "parent": "engineering",
4439+ "members": [
4440+ "ana"
4441+ ]
4442+ },
4443+ "response": {
4444+ "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4445+ "workspace": "flagon-io",
4446+ "slug": "backend",
4447+ "name": "Backend",
4448+ "description": "The API and the services behind it.",
4449+ "visibility": "visible",
4450+ "parent": {
4451+ "slug": "engineering",
4452+ "name": "Engineering"
4453+ },
4454+ "notify": true,
4455+ "review_assignment": {
4456+ "enabled": false,
4457+ "algorithm": "round_robin",
4458+ "count": 1,
4459+ "skip_busy": false,
4460+ "busy_at": 5,
4461+ "include_child_teams": false,
4462+ "excluded": [],
4463+ "notify_team": false
4464+ },
4465+ "members_count": 2,
4466+ "repos_count": 0,
4467+ "child_teams_count": 0,
4468+ "viewer_role": "maintainer",
4469+ "can_manage": true,
4470+ "created_at": "2026-10-06T15:02:11.480Z",
4471+ "updated_at": "2026-10-06T15:02:11.480Z"
4472+ },
4473+ "notes": "You become the team's maintainer. Refused with `403` for a member when the workspace's `team_creation` is `owners`. `slug` is made from `name` when left out (`Web & Mobile` becomes `web-mobile`), and `409` says one is taken. A workspace has at most 500 teams, nested at most 8 deep; `name` is at most 80 characters and `description` 280. A `secret` team cannot have a parent or child teams. Refused with `403` for an agent's or a workspace's token. See [Teams](/guides/teams/)."
4474+ },
4475+ "get_team": {
4476+ "params": {
4477+ "workspace": "flagon-io",
4478+ "team": "backend"
4479+ },
4480+ "response": {
4481+ "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4482+ "workspace": "flagon-io",
4483+ "slug": "backend",
4484+ "name": "Backend",
4485+ "description": "The API and the services behind it.",
4486+ "visibility": "visible",
4487+ "parent": {
4488+ "slug": "engineering",
4489+ "name": "Engineering"
4490+ },
4491+ "notify": true,
4492+ "review_assignment": {
4493+ "enabled": false,
4494+ "algorithm": "round_robin",
4495+ "count": 1,
4496+ "skip_busy": false,
4497+ "busy_at": 5,
4498+ "include_child_teams": false,
4499+ "excluded": [],
4500+ "notify_team": false
4501+ },
4502+ "members_count": 4,
4503+ "repos_count": 2,
4504+ "child_teams_count": 1,
4505+ "viewer_role": "maintainer",
4506+ "can_manage": true,
4507+ "created_at": "2026-10-06T15:02:11.480Z",
4508+ "updated_at": "2026-10-06T15:02:11.480Z"
4509+ },
4510+ "notes": "`404` for a team that does not exist, or a secret one you are not in, unless you are an owner."
4511+ },
4512+ "update_team": {
4513+ "params": {
4514+ "workspace": "flagon-io",
4515+ "team": "backend"
4516+ },
4517+ "request": {
4518+ "description": "The API, the services behind it, and their on-call.",
4519+ "visibility": "secret",
4520+ "parent": ""
4521+ },
4522+ "response": {
4523+ "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4524+ "workspace": "flagon-io",
4525+ "slug": "backend",
4526+ "name": "Backend",
4527+ "description": "The API, the services behind it, and their on-call.",
4528+ "visibility": "secret",
4529+ "parent": null,
4530+ "notify": true,
4531+ "review_assignment": {
4532+ "enabled": false,
4533+ "algorithm": "round_robin",
4534+ "count": 1,
4535+ "skip_busy": false,
4536+ "busy_at": 5,
4537+ "include_child_teams": false,
4538+ "excluded": [],
4539+ "notify_team": false
4540+ },
4541+ "members_count": 4,
4542+ "repos_count": 2,
4543+ "child_teams_count": 1,
4544+ "viewer_role": "maintainer",
4545+ "can_manage": true,
4546+ "created_at": "2026-10-06T15:02:11.480Z",
4547+ "updated_at": "2026-10-07T09:41:52.006Z"
4548+ },
4549+ "notes": "Only the fields given change. `parent` set to `\"\"` takes the team out from under its parent; a team cannot be nested under itself or one of its own child teams. A new `slug` changes how it is mentioned: `@flagon-io/backend` no longer reaches it. `review_assignment` takes the fields [`set_team_review_assignment`](/reference/api/teams/set-team-review-assignment/) does. Owners of the workspace and the team's maintainers (`403` otherwise)."
4550+ },
4551+ "delete_team": {
4552+ "params": {
4553+ "workspace": "flagon-io",
4554+ "team": "backend"
4555+ },
4556+ "response": true,
4557+ "notes": "Its child teams move up to its parent, or to the top when it has none. The roles it gave on repositories are taken away, and it is no longer asked to review. Owners of the workspace and the team's maintainers (`403` otherwise)."
4558+ },
4559+ "list_team_members": {
4560+ "params": {
4561+ "workspace": "flagon-io",
4562+ "team": "backend"
4563+ },
4564+ "query": {
4565+ "include_child_teams": "true"
4566+ },
4567+ "response": [
4568+ {
4569+ "username": "syntaqx",
4570+ "name": "Chase Pierce",
4571+ "avatar": null,
4572+ "role": "maintainer",
4573+ "via": null
4574+ },
4575+ {
4576+ "username": "ana",
4577+ "name": "Ana Lima",
4578+ "avatar": null,
4579+ "role": "member",
4580+ "via": null
4581+ },
4582+ {
4583+ "username": "bo",
4584+ "name": null,
4585+ "avatar": null,
4586+ "role": "member",
4587+ "via": "payments"
4588+ }
4589+ ],
4590+ "notes": "Maintainers come first, then members, each by username. With `include_child_teams`, the people of its child teams (and theirs) follow, each with `via`, the child team they are in; someone in both is listed once, as the team's own."
4591+ },
4592+ "set_team_member": {
4593+ "params": {
4594+ "workspace": "flagon-io",
4595+ "team": "backend",
4596+ "username": "ana"
4597+ },
4598+ "request": {
4599+ "role": "maintainer"
4600+ },
4601+ "response": {
4602+ "username": "ana",
4603+ "name": "Ana Lima",
4604+ "avatar": null,
4605+ "role": "maintainer",
4606+ "via": null
4607+ },
4608+ "notes": "`role` is `member` (the default) or `maintainer`. `422` when they are not a member of the workspace: add them to it first. Owners of the workspace and the team's maintainers (`403` otherwise)."
4609+ },
4610+ "remove_team_member": {
4611+ "params": {
4612+ "workspace": "flagon-io",
4613+ "team": "backend",
4614+ "username": "ana"
4615+ },
4616+ "response": true,
4617+ "notes": "Anyone may take themselves out of a team. Leaving the workspace takes a person out of all its teams."
4618+ },
4619+ "list_child_teams": {
4620+ "params": {
4621+ "workspace": "flagon-io",
4622+ "team": "engineering"
4623+ },
4624+ "response": [
4625+ {
4626+ "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4627+ "workspace": "flagon-io",
4628+ "slug": "backend",
4629+ "name": "Backend",
4630+ "description": "The API and the services behind it.",
4631+ "visibility": "visible",
4632+ "parent": {
4633+ "slug": "engineering",
4634+ "name": "Engineering"
4635+ },
4636+ "notify": true,
4637+ "review_assignment": {
4638+ "enabled": false,
4639+ "algorithm": "round_robin",
4640+ "count": 1,
4641+ "skip_busy": false,
4642+ "busy_at": 5,
4643+ "include_child_teams": false,
4644+ "excluded": [],
4645+ "notify_team": false
4646+ },
4647+ "members_count": 4,
4648+ "repos_count": 2,
4649+ "child_teams_count": 0,
4650+ "viewer_role": "maintainer",
4651+ "can_manage": true,
4652+ "created_at": "2026-10-06T15:02:11.480Z",
4653+ "updated_at": "2026-10-06T15:02:11.480Z"
4654+ }
4655+ ],
4656+ "notes": "Only the teams directly under it; read each one's own with this again. A child team inherits its parent's roles on repositories, and a mention or review request for the parent reaches its people too."
4657+ },
4658+ "list_team_repos": {
4659+ "params": {
4660+ "workspace": "flagon-io",
4661+ "team": "backend"
4662+ },
4663+ "response": [
4664+ {
4665+ "repo": "flagon-io/hello",
4666+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4667+ "role": "write",
4668+ "inherited_from": null
4669+ },
4670+ {
4671+ "repo": "flagon-io/docs",
4672+ "repo_id": "rep_01m3m5r2a8c4e6g8j0m2p4r6t8",
4673+ "role": "read",
4674+ "inherited_from": "engineering"
4675+ }
4676+ ],
4677+ "notes": "A role inherited from a parent team names it in `inherited_from`. Where the team has a role of its own on the same repository, the higher one is listed. Only repositories you can see are listed."
4678+ },
4679+ "set_team_repo": {
4680+ "params": {
4681+ "workspace": "flagon-io",
4682+ "team": "backend",
4683+ "repo": "hello"
4684+ },
4685+ "request": {
4686+ "role": "maintain"
4687+ },
4688+ "response": {
4689+ "repo": "flagon-io/hello",
4690+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
4691+ "role": "maintain",
4692+ "inherited_from": null
4693+ },
4694+ "notes": "`repo` in the path is the repository's name in the team's workspace; a team has roles only on its own workspace's repositories. `role` is `read`, `triage`, `write`, `maintain` or `admin`. Everyone in the team and its child teams gets it; someone with a higher role otherwise keeps that. Needs the Admin role on the repository (`403` otherwise), and the `access:admin` scope. See [Access and roles](/guides/access-and-roles/)."
4695+ },
4696+ "remove_team_repo": {
4697+ "params": {
4698+ "workspace": "flagon-io",
4699+ "team": "backend",
4700+ "repo": "hello"
4701+ },
4702+ "response": true,
4703+ "notes": "A role the team inherits from a parent is taken away on the parent. Needs the Admin role on the repository, or to be an owner or one of the team's maintainers."
4704+ },
4705+ "set_team_review_assignment": {
4706+ "params": {
4707+ "workspace": "flagon-io",
4708+ "team": "backend"
4709+ },
4710+ "request": {
4711+ "enabled": true,
4712+ "algorithm": "load_balance",
4713+ "count": 2,
4714+ "skip_busy": true,
4715+ "busy_at": 5,
4716+ "excluded": [
4717+ "syntaqx"
4718+ ]
4719+ },
4720+ "response": {
4721+ "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4722+ "workspace": "flagon-io",
4723+ "slug": "backend",
4724+ "name": "Backend",
4725+ "description": "The API and the services behind it.",
4726+ "visibility": "visible",
4727+ "parent": {
4728+ "slug": "engineering",
4729+ "name": "Engineering"
4730+ },
4731+ "notify": true,
4732+ "review_assignment": {
4733+ "enabled": true,
4734+ "algorithm": "load_balance",
4735+ "count": 2,
4736+ "skip_busy": true,
4737+ "busy_at": 5,
4738+ "include_child_teams": false,
4739+ "excluded": [
4740+ "syntaqx"
4741+ ],
4742+ "notify_team": false
4743+ },
4744+ "members_count": 4,
4745+ "repos_count": 2,
4746+ "child_teams_count": 1,
4747+ "viewer_role": "maintainer",
4748+ "can_manage": true,
4749+ "created_at": "2026-10-06T15:02:11.480Z",
4750+ "updated_at": "2026-10-07T09:44:03.512Z"
4751+ },
4752+ "notes": "| Field | |\n| --- | --- |\n| `enabled` | Off, everyone in the team is asked. On, `count` people are picked and asked, and the team stays shown as asked beside them. |\n| `algorithm` | `round_robin`: whoever this team asked least recently. `load_balance`: whoever has the fewest pull requests waiting on their review. |\n| `count` | How many to pick, 1 to 10. People from the team already asked count towards it. |\n| `skip_busy`, `busy_at` | Leave out anyone with `busy_at` (1 to 100) or more pull requests waiting on their review. |\n| `include_child_teams` | Also pick from its child teams' people. |\n| `excluded` | Usernames never picked. Replaces the whole list. |\n| `notify_team` | Also tell the rest of the team when people are picked. |\n\nFields left out keep their value. The pull request's author is never picked. See [Teams](/guides/teams/)."
4753+ },
4754+ "list_user_teams": {
4755+ "params": {
4756+ "workspace": "flagon-io",
4757+ "username": "ana"
4758+ },
4759+ "response": [
4760+ {
4761+ "id": "team_01m52k8d3f7h1k5n9r3v7z1c5g",
4762+ "workspace": "flagon-io",
4763+ "slug": "backend",
4764+ "name": "Backend",
4765+ "description": "The API and the services behind it.",
4766+ "visibility": "visible",
4767+ "parent": {
4768+ "slug": "engineering",
4769+ "name": "Engineering"
4770+ },
4771+ "notify": true,
4772+ "review_assignment": {
4773+ "enabled": false,
4774+ "algorithm": "round_robin",
4775+ "count": 1,
4776+ "skip_busy": false,
4777+ "busy_at": 5,
4778+ "include_child_teams": false,
4779+ "excluded": [],
4780+ "notify_team": false
4781+ },
4782+ "members_count": 4,
4783+ "repos_count": 2,
4784+ "child_teams_count": 1,
4785+ "viewer_role": null,
4786+ "can_manage": false,
4787+ "created_at": "2026-10-06T15:02:11.480Z",
4788+ "updated_at": "2026-10-06T15:02:11.480Z"
4789+ }
4790+ ],
4791+ "notes": "Only the teams they are in themselves, not the parents those teams are under. Secret teams you are not in are left out unless you are an owner. `403` for anyone who is not a member of the workspace."
4792+ },
4793+ "list_security_alerts": {
4794+ "params": {
4795+ "owner": "flagon-io",
4796+ "name": "hello"
4797+ },
4798+ "query": {
4799+ "state": "open"
4800+ },
4801+ "response": [
4802+ {
4803+ "kind": "secret",
4804+ "id": "sec_01kp4a7b2c3d4e5f6g7h8j9k0m",
4805+ "state": "dismissed",
4806+ "secret_type": "aws_access_key",
4807+ "label": "an AWS access key",
4808+ "path": "test/fixtures/aws.env",
4809+ "line": 3,
4810+ "commit": "9f2c1e04b7d3a8e6f5c2b1a0d9e8f7c6b5a4d3e2",
4811+ "preview": "AKIA…MPLE",
4812+ "status": "allowed",
4813+ "source": "history",
4814+ "test_value": "the documented example key",
4815+ "found_by": null,
4816+ "found_at": "2026-10-01T12:00:00.000Z",
4817+ "dismissed_reason": "used_in_tests",
4818+ "dismissed_comment": "Only in the test fixtures.",
4819+ "dismissed_by": "syntaqx",
4820+ "dismissed_at": "2026-10-02T09:15:00.000Z"
4821+ },
4822+ {
4823+ "kind": "dependency",
4824+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
4825+ "state": "open",
4826+ "ecosystem": "npm",
4827+ "package": "lodash",
4828+ "version": "4.17.20",
4829+ "manifest": "package-lock.json",
4830+ "advisory": "GHSA-35jh-r3h4-6jhm",
4831+ "osv_id": "GHSA-35jh-r3h4-6jhm",
4832+ "summary": "Command Injection in lodash",
4833+ "severity": "high",
4834+ "fixed_version": "4.17.21",
4835+ "fixed_at": null,
4836+ "update": {
4837+ "state": "open",
4838+ "target": "4.17.21",
4839+ "branch": "g1t/security/lodash-4.17.21",
4840+ "pull": 42,
4841+ "issue": null,
4842+ "error": null,
4843+ "updated_at": "2026-10-01T12:20:00.000Z"
4844+ },
4845+ "found_at": "2026-10-01T12:00:00.000Z",
4846+ "dismissed_reason": null,
4847+ "dismissed_comment": null,
4848+ "dismissed_by": null,
4849+ "dismissed_at": null
4850+ }
4851+ ],
4852+ "notes": "Secrets come first, then dependencies. Fields only one kind has are left out of the other: a secret has `secret_type`, `label`, `path`, `line`, `commit`, `preview`, `status` (`open`, `blocked`, `allowed` or `resolved`), `source` (`push` or `history`), `test_value` and `found_by`; a dependency has `ecosystem`, `package`, `version`, `manifest`, `advisory`, `osv_id`, `summary`, `severity`, `fixed_version` (null when no patched version is available), `fixed_at` and `update`, the pull request g1t opens to upgrade it. `dismissed_reason`, `dismissed_comment`, `dismissed_by` and `dismissed_at` are null while an alert is open; a secret fixed by being revoked keeps them. `422` for a `state` or `kind` it does not know, and `404` for anyone without the Write role. See [Security](/guides/security/)."
4853+ },
4854+ "dismiss_security_alert": {
4855+ "params": {
4856+ "owner": "flagon-io",
4857+ "name": "hello",
4858+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n"
4859+ },
4860+ "request": {
4861+ "reason": "tolerable_risk",
4862+ "comment": "Only the build uses it, on trusted input."
4863+ },
4864+ "response": {
4865+ "kind": "dependency",
4866+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
4867+ "state": "dismissed",
4868+ "ecosystem": "npm",
4869+ "package": "lodash",
4870+ "version": "4.17.20",
4871+ "manifest": "package-lock.json",
4872+ "advisory": "GHSA-35jh-r3h4-6jhm",
4873+ "osv_id": "GHSA-35jh-r3h4-6jhm",
4874+ "summary": "Command Injection in lodash",
4875+ "severity": "high",
4876+ "fixed_version": "4.17.21",
4877+ "fixed_at": null,
4878+ "update": {
4879+ "state": "open",
4880+ "target": "4.17.21",
4881+ "branch": "g1t/security/lodash-4.17.21",
4882+ "pull": 42,
4883+ "issue": null,
4884+ "error": null,
4885+ "updated_at": "2026-10-01T12:20:00.000Z"
4886+ },
4887+ "found_at": "2026-10-01T12:00:00.000Z",
4888+ "dismissed_reason": "tolerable_risk",
4889+ "dismissed_comment": "Only the build uses it, on trusted input.",
4890+ "dismissed_by": "syntaqx",
4891+ "dismissed_at": "2026-10-06T10:00:00.000Z"
4892+ },
4893+ "notes": "| Kind | Reasons |\n| --- | --- |\n| `secret` | `false_positive`, `used_in_tests`, `revoked`, `wont_fix` |\n| `dependency` | `fix_started`, `no_bandwidth`, `tolerable_risk`, `inaccurate`, `not_used` |\n\nA reason for the other kind of alert, or one not in the table, is refused with `422`. A secret dismissed as `revoked` becomes `fixed`; with any other reason it becomes `dismissed` and pushes that carry it go through. Dismissing a secret needs the Admin role on the repository; a dependency needs the Write role. A token needs `repo:admin` for either, and a g1t agent’s token never dismisses alerts."
4894+ },
4895+ "reopen_security_alert": {
4896+ "params": {
4897+ "owner": "flagon-io",
4898+ "name": "hello",
4899+ "id": "sec_01kp4a7b2c3d4e5f6g7h8j9k0m"
4900+ },
4901+ "response": {
4902+ "kind": "secret",
4903+ "id": "sec_01kp4a7b2c3d4e5f6g7h8j9k0m",
4904+ "state": "open",
4905+ "secret_type": "aws_access_key",
4906+ "label": "an AWS access key",
4907+ "path": "test/fixtures/aws.env",
4908+ "line": 3,
4909+ "commit": "9f2c1e04b7d3a8e6f5c2b1a0d9e8f7c6b5a4d3e2",
4910+ "preview": "AKIA…MPLE",
4911+ "status": "open",
4912+ "source": "history",
4913+ "test_value": "the documented example key",
4914+ "found_by": null,
4915+ "found_at": "2026-10-01T12:00:00.000Z",
4916+ "dismissed_reason": null,
4917+ "dismissed_comment": null,
4918+ "dismissed_by": null,
4919+ "dismissed_at": null
4920+ },
4921+ "notes": "The alert is `open` again, and a reopened secret stops pushes that carry it. The same roles as dismissing: Admin for a secret, Write for a dependency."
4922+ },
4923+ "list_notifications": {
4924+ "query": {
4925+ "participating": "true"
4926+ },
4927+ "response": {
4928+ "items": [
4929+ {
4930+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
4931+ "reason": "review_requested",
4932+ "severity": "warning",
4933+ "title": "ada asked you to review flagon-io/hello#14",
4934+ "body": "Add a greeting to the README",
4935+ "event": "pull.review_requested",
4936+ "repo": "flagon-io/hello",
4937+ "workspace": "flagon-io",
4938+ "subject": "pull",
4939+ "number": 14,
4940+ "url": "/flagon-io/hello/pull/14",
4941+ "actor": "ada",
4942+ "count": 3,
4943+ "created_at": "2026-10-06T15:02:11.000Z",
4944+ "updated_at": "2026-10-07T09:41:30.000Z",
4945+ "read_at": null,
4946+ "done_at": null,
4947+ "saved": false,
4948+ "snoozed_until": null
4949+ },
4950+ {
4951+ "id": "ntf_01kp7k9a8b7c6d5e4f3g2h1j0k",
4952+ "reason": "ci_activity",
4953+ "severity": "error",
4954+ "title": "Production of hello failed to deploy",
4955+ "body": "The build failed: npm run build exited with 1.",
4956+ "event": "deployment.failed",
4957+ "repo": "flagon-io/hello",
4958+ "workspace": "flagon-io",
4959+ "subject": "deploy",
4960+ "number": null,
4961+ "url": "/flagon-io/hello/deployments/dpl_01kp7k8z7y6x5w4v3t2s1r0q9p",
4962+ "actor": "syntaqx",
4963+ "count": 1,
4964+ "created_at": "2026-10-07T08:12:40.000Z",
4965+ "updated_at": "2026-10-07T08:12:40.000Z",
4966+ "read_at": null,
4967+ "done_at": null,
4968+ "saved": false,
4969+ "snoozed_until": null
4970+ }
4971+ ],
4972+ "next": null
4973+ },
4974+ "notes": "Unread threads only, unless `all=true`. Threads that wait on you (an agent, or a review asked of you) have severity `warning`.\n\n| `reason` | You were told because |\n| --- | --- |\n| `agent` | An agent is waiting on you: it asked a question, or g1t stopped until a person steps in |\n| `review_requested` | You were asked to review |\n| `assign` | You were assigned |\n| `mention` | Someone mentioned you by `@username` |\n| `ci_activity` | Checks, a workflow or a deployment on your work finished |\n| `security_alert` | A security alert on a repository you look after |\n| `state_change` | It was closed, reopened or merged |\n| `author` | You opened it, or asked g1t for it |\n| `comment` | You commented on it |\n| `manual` | You subscribed to it by hand |\n| `subscribed` | You watch its repository |\n\nWith `participating=true`, threads you only follow (`manual`, `subscribed`) are left out. For the next page, pass `next` as `cursor`; `next` is null on the last."
4975+ },
4976+ "list_repo_notifications": {
4977+ "params": {
4978+ "owner": "flagon-io",
4979+ "name": "hello"
4980+ },
4981+ "query": {
4982+ "all": "true"
4983+ },
4984+ "response": {
4985+ "items": [
4986+ {
4987+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
4988+ "reason": "review_requested",
4989+ "severity": "warning",
4990+ "title": "ada asked you to review flagon-io/hello#14",
4991+ "body": "Add a greeting to the README",
4992+ "event": "pull.review_requested",
4993+ "repo": "flagon-io/hello",
4994+ "workspace": "flagon-io",
4995+ "subject": "pull",
4996+ "number": 14,
4997+ "url": "/flagon-io/hello/pull/14",
4998+ "actor": "ada",
4999+ "count": 3,
5000+ "created_at": "2026-10-06T15:02:11.000Z",
5001+ "updated_at": "2026-10-07T09:41:30.000Z",
5002+ "read_at": "2026-10-07T09:50:00.000Z",
5003+ "done_at": null,
5004+ "saved": false,
5005+ "snoozed_until": null
5006+ },
5007+ {
5008+ "id": "ntf_01kp7k9a8b7c6d5e4f3g2h1j0k",
5009+ "reason": "ci_activity",
5010+ "severity": "error",
5011+ "title": "Production of hello failed to deploy",
5012+ "body": "The build failed: npm run build exited with 1.",
5013+ "event": "deployment.failed",
5014+ "repo": "flagon-io/hello",
5015+ "workspace": "flagon-io",
5016+ "subject": "deploy",
5017+ "number": null,
5018+ "url": "/flagon-io/hello/deployments/dpl_01kp7k8z7y6x5w4v3t2s1r0q9p",
5019+ "actor": "syntaqx",
5020+ "count": 1,
5021+ "created_at": "2026-10-07T08:12:40.000Z",
5022+ "updated_at": "2026-10-07T08:12:40.000Z",
5023+ "read_at": null,
5024+ "done_at": null,
5025+ "saved": false,
5026+ "snoozed_until": null
5027+ }
5028+ ],
5029+ "next": "ntf_01kp7k9a8b7c6d5e4f3g2h1j0k"
5030+ },
5031+ "notes": "The same as `GET /notifications`, for one repository you can read."
5032+ },
5033+ "mark_notifications_read": {
5034+ "request": {
5035+ "last_read_at": "2026-10-07T10:00:00Z"
5036+ },
5037+ "response": {
5038+ "marked": 12,
5039+ "last_read_at": "2026-10-07T10:00:00.000Z"
5040+ },
5041+ "notes": "Threads with activity after `last_read_at` stay unread, so send the time you last listed them."
5042+ },
5043+ "mark_repo_notifications_read": {
5044+ "params": {
5045+ "owner": "flagon-io",
5046+ "name": "hello"
5047+ },
5048+ "request": {},
5049+ "response": {
5050+ "marked": 3,
5051+ "last_read_at": "2026-10-07T10:02:41.512Z"
5052+ }
5053+ },
5054+ "get_notification_thread": {
5055+ "params": {
5056+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5057+ },
5058+ "response": {
5059+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5060+ "reason": "review_requested",
5061+ "severity": "warning",
5062+ "title": "ada asked you to review flagon-io/hello#14",
5063+ "body": "Add a greeting to the README",
5064+ "event": "pull.review_requested",
5065+ "repo": "flagon-io/hello",
5066+ "workspace": "flagon-io",
5067+ "subject": "pull",
5068+ "number": 14,
5069+ "url": "/flagon-io/hello/pull/14",
5070+ "actor": "ada",
5071+ "count": 3,
5072+ "created_at": "2026-10-06T15:02:11.000Z",
5073+ "updated_at": "2026-10-07T09:41:30.000Z",
5074+ "read_at": null,
5075+ "done_at": null,
5076+ "saved": false,
5077+ "snoozed_until": null,
5078+ "activity": [
5079+ {
5080+ "reason": "review_requested",
5081+ "severity": "warning",
5082+ "title": "ada asked you to review flagon-io/hello#14",
5083+ "body": "Add a greeting to the README",
5084+ "event": "pull.review_requested",
5085+ "actor": "ada",
5086+ "created_at": "2026-10-07T09:41:30.000Z"
5087+ },
5088+ {
5089+ "reason": "comment",
5090+ "severity": "info",
5091+ "title": "ada commented on flagon-io/hello#14",
5092+ "body": "Pushed the fix for the heading.",
5093+ "event": "comment.created",
5094+ "actor": "ada",
5095+ "created_at": "2026-10-06T18:20:02.000Z"
5096+ },
5097+ {
5098+ "reason": "comment",
5099+ "severity": "info",
5100+ "title": "g1t commented on flagon-io/hello#14",
5101+ "body": "The heading level is off by one.",
5102+ "event": "comment.created",
5103+ "actor": "g1t",
5104+ "created_at": "2026-10-06T15:02:11.000Z"
5105+ }
5106+ ],
5107+ "subscription": {
5108+ "subscribed": true,
5109+ "ignored": false,
5110+ "reason": "review_requested",
5111+ "repo": "flagon-io/hello",
5112+ "number": 14,
5113+ "updated_at": null
5114+ }
5115+ },
5116+ "notes": "`activity` keeps the last 10 things that happened on the thread, newest first; `count` is how many there have been. `subscription` is null for a workflow or a deployment, which nobody subscribes to."
5117+ },
5118+ "mark_thread_read": {
5119+ "params": {
5120+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5121+ },
5122+ "request": {},
5123+ "response": {
5124+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5125+ "reason": "review_requested",
5126+ "severity": "warning",
5127+ "title": "ada asked you to review flagon-io/hello#14",
5128+ "body": "Add a greeting to the README",
5129+ "event": "pull.review_requested",
5130+ "repo": "flagon-io/hello",
5131+ "workspace": "flagon-io",
5132+ "subject": "pull",
5133+ "number": 14,
5134+ "url": "/flagon-io/hello/pull/14",
5135+ "actor": "ada",
5136+ "count": 3,
5137+ "created_at": "2026-10-06T15:02:11.000Z",
5138+ "updated_at": "2026-10-07T09:41:30.000Z",
5139+ "read_at": "2026-10-07T10:03:00.000Z",
5140+ "done_at": null,
5141+ "saved": false,
5142+ "snoozed_until": null,
5143+ "activity": [
5144+ {
5145+ "reason": "review_requested",
5146+ "severity": "warning",
5147+ "title": "ada asked you to review flagon-io/hello#14",
5148+ "body": "Add a greeting to the README",
5149+ "event": "pull.review_requested",
5150+ "actor": "ada",
5151+ "created_at": "2026-10-07T09:41:30.000Z"
5152+ },
5153+ {
5154+ "reason": "comment",
5155+ "severity": "info",
5156+ "title": "ada commented on flagon-io/hello#14",
5157+ "body": "Pushed the fix for the heading.",
5158+ "event": "comment.created",
5159+ "actor": "ada",
5160+ "created_at": "2026-10-06T18:20:02.000Z"
5161+ },
5162+ {
5163+ "reason": "comment",
5164+ "severity": "info",
5165+ "title": "g1t commented on flagon-io/hello#14",
5166+ "body": "The heading level is off by one.",
5167+ "event": "comment.created",
5168+ "actor": "g1t",
5169+ "created_at": "2026-10-06T15:02:11.000Z"
5170+ }
5171+ ],
5172+ "subscription": {
5173+ "subscribed": true,
5174+ "ignored": false,
5175+ "reason": "review_requested",
5176+ "repo": "flagon-io/hello",
5177+ "number": 14,
5178+ "updated_at": null
5179+ }
5180+ }
5181+ },
5182+ "mark_thread_done": {
5183+ "params": {
5184+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5185+ },
5186+ "response": {
5187+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5188+ "reason": "review_requested",
5189+ "severity": "warning",
5190+ "title": "ada asked you to review flagon-io/hello#14",
5191+ "body": "Add a greeting to the README",
5192+ "event": "pull.review_requested",
5193+ "repo": "flagon-io/hello",
5194+ "workspace": "flagon-io",
5195+ "subject": "pull",
5196+ "number": 14,
5197+ "url": "/flagon-io/hello/pull/14",
5198+ "actor": "ada",
5199+ "count": 3,
5200+ "created_at": "2026-10-06T15:02:11.000Z",
5201+ "updated_at": "2026-10-07T09:41:30.000Z",
5202+ "read_at": "2026-10-07T10:03:00.000Z",
5203+ "done_at": "2026-10-07T10:03:00.000Z",
5204+ "saved": false,
5205+ "snoozed_until": null,
5206+ "activity": [
5207+ {
5208+ "reason": "review_requested",
5209+ "severity": "warning",
5210+ "title": "ada asked you to review flagon-io/hello#14",
5211+ "body": "Add a greeting to the README",
5212+ "event": "pull.review_requested",
5213+ "actor": "ada",
5214+ "created_at": "2026-10-07T09:41:30.000Z"
5215+ },
5216+ {
5217+ "reason": "comment",
5218+ "severity": "info",
5219+ "title": "ada commented on flagon-io/hello#14",
5220+ "body": "Pushed the fix for the heading.",
5221+ "event": "comment.created",
5222+ "actor": "ada",
5223+ "created_at": "2026-10-06T18:20:02.000Z"
5224+ },
5225+ {
5226+ "reason": "comment",
5227+ "severity": "info",
5228+ "title": "g1t commented on flagon-io/hello#14",
5229+ "body": "The heading level is off by one.",
5230+ "event": "comment.created",
5231+ "actor": "g1t",
5232+ "created_at": "2026-10-06T15:02:11.000Z"
5233+ }
5234+ ],
5235+ "subscription": {
5236+ "subscribed": true,
5237+ "ignored": false,
5238+ "reason": "review_requested",
5239+ "repo": "flagon-io/hello",
5240+ "number": 14,
5241+ "updated_at": null
5242+ }
5243+ },
5244+ "notes": "New activity on a done thread brings it back to the inbox, unread."
5245+ },
5246+ "save_thread": {
5247+ "params": {
5248+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5249+ },
5250+ "request": {},
5251+ "response": {
5252+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5253+ "reason": "review_requested",
5254+ "severity": "warning",
5255+ "title": "ada asked you to review flagon-io/hello#14",
5256+ "body": "Add a greeting to the README",
5257+ "event": "pull.review_requested",
5258+ "repo": "flagon-io/hello",
5259+ "workspace": "flagon-io",
5260+ "subject": "pull",
5261+ "number": 14,
5262+ "url": "/flagon-io/hello/pull/14",
5263+ "actor": "ada",
5264+ "count": 3,
5265+ "created_at": "2026-10-06T15:02:11.000Z",
5266+ "updated_at": "2026-10-07T09:41:30.000Z",
5267+ "read_at": null,
5268+ "done_at": null,
5269+ "saved": true,
5270+ "snoozed_until": null,
5271+ "activity": [
5272+ {
5273+ "reason": "review_requested",
5274+ "severity": "warning",
5275+ "title": "ada asked you to review flagon-io/hello#14",
5276+ "body": "Add a greeting to the README",
5277+ "event": "pull.review_requested",
5278+ "actor": "ada",
5279+ "created_at": "2026-10-07T09:41:30.000Z"
5280+ },
5281+ {
5282+ "reason": "comment",
5283+ "severity": "info",
5284+ "title": "ada commented on flagon-io/hello#14",
5285+ "body": "Pushed the fix for the heading.",
5286+ "event": "comment.created",
5287+ "actor": "ada",
5288+ "created_at": "2026-10-06T18:20:02.000Z"
5289+ },
5290+ {
5291+ "reason": "comment",
5292+ "severity": "info",
5293+ "title": "g1t commented on flagon-io/hello#14",
5294+ "body": "The heading level is off by one.",
5295+ "event": "comment.created",
5296+ "actor": "g1t",
5297+ "created_at": "2026-10-06T15:02:11.000Z"
5298+ }
5299+ ],
5300+ "subscription": {
5301+ "subscribed": true,
5302+ "ignored": false,
5303+ "reason": "review_requested",
5304+ "repo": "flagon-io/hello",
5305+ "number": 14,
5306+ "updated_at": null
5307+ }
5308+ }
5309+ },
5310+ "unsave_thread": {
5311+ "params": {
5312+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5313+ },
5314+ "response": {
5315+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5316+ "reason": "review_requested",
5317+ "severity": "warning",
5318+ "title": "ada asked you to review flagon-io/hello#14",
5319+ "body": "Add a greeting to the README",
5320+ "event": "pull.review_requested",
5321+ "repo": "flagon-io/hello",
5322+ "workspace": "flagon-io",
5323+ "subject": "pull",
5324+ "number": 14,
5325+ "url": "/flagon-io/hello/pull/14",
5326+ "actor": "ada",
5327+ "count": 3,
5328+ "created_at": "2026-10-06T15:02:11.000Z",
5329+ "updated_at": "2026-10-07T09:41:30.000Z",
5330+ "read_at": null,
5331+ "done_at": null,
5332+ "saved": false,
5333+ "snoozed_until": null,
5334+ "activity": [
5335+ {
5336+ "reason": "review_requested",
5337+ "severity": "warning",
5338+ "title": "ada asked you to review flagon-io/hello#14",
5339+ "body": "Add a greeting to the README",
5340+ "event": "pull.review_requested",
5341+ "actor": "ada",
5342+ "created_at": "2026-10-07T09:41:30.000Z"
5343+ },
5344+ {
5345+ "reason": "comment",
5346+ "severity": "info",
5347+ "title": "ada commented on flagon-io/hello#14",
5348+ "body": "Pushed the fix for the heading.",
5349+ "event": "comment.created",
5350+ "actor": "ada",
5351+ "created_at": "2026-10-06T18:20:02.000Z"
5352+ },
5353+ {
5354+ "reason": "comment",
5355+ "severity": "info",
5356+ "title": "g1t commented on flagon-io/hello#14",
5357+ "body": "The heading level is off by one.",
5358+ "event": "comment.created",
5359+ "actor": "g1t",
5360+ "created_at": "2026-10-06T15:02:11.000Z"
5361+ }
5362+ ],
5363+ "subscription": {
5364+ "subscribed": true,
5365+ "ignored": false,
5366+ "reason": "review_requested",
5367+ "repo": "flagon-io/hello",
5368+ "number": 14,
5369+ "updated_at": null
5370+ }
5371+ }
5372+ },
5373+ "snooze_thread": {
5374+ "params": {
5375+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5376+ },
5377+ "request": {
5378+ "until": "2026-10-08T09:00:00Z"
5379+ },
5380+ "response": {
5381+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5382+ "reason": "review_requested",
5383+ "severity": "warning",
5384+ "title": "ada asked you to review flagon-io/hello#14",
5385+ "body": "Add a greeting to the README",
5386+ "event": "pull.review_requested",
5387+ "repo": "flagon-io/hello",
5388+ "workspace": "flagon-io",
5389+ "subject": "pull",
5390+ "number": 14,
5391+ "url": "/flagon-io/hello/pull/14",
5392+ "actor": "ada",
5393+ "count": 3,
5394+ "created_at": "2026-10-06T15:02:11.000Z",
5395+ "updated_at": "2026-10-07T09:41:30.000Z",
5396+ "read_at": "2026-10-07T10:03:00.000Z",
5397+ "done_at": null,
5398+ "saved": false,
5399+ "snoozed_until": "2026-10-08T09:00:00.000Z",
5400+ "activity": [
5401+ {
5402+ "reason": "review_requested",
5403+ "severity": "warning",
5404+ "title": "ada asked you to review flagon-io/hello#14",
5405+ "body": "Add a greeting to the README",
5406+ "event": "pull.review_requested",
5407+ "actor": "ada",
5408+ "created_at": "2026-10-07T09:41:30.000Z"
5409+ },
5410+ {
5411+ "reason": "comment",
5412+ "severity": "info",
5413+ "title": "ada commented on flagon-io/hello#14",
5414+ "body": "Pushed the fix for the heading.",
5415+ "event": "comment.created",
5416+ "actor": "ada",
5417+ "created_at": "2026-10-06T18:20:02.000Z"
5418+ },
5419+ {
5420+ "reason": "comment",
5421+ "severity": "info",
5422+ "title": "g1t commented on flagon-io/hello#14",
5423+ "body": "The heading level is off by one.",
5424+ "event": "comment.created",
5425+ "actor": "g1t",
5426+ "created_at": "2026-10-06T15:02:11.000Z"
5427+ }
5428+ ],
5429+ "subscription": {
5430+ "subscribed": true,
5431+ "ignored": false,
5432+ "reason": "review_requested",
5433+ "repo": "flagon-io/hello",
5434+ "number": 14,
5435+ "updated_at": null
5436+ }
5437+ }
5438+ },
5439+ "unsnooze_thread": {
5440+ "params": {
5441+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5442+ },
5443+ "response": {
5444+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a",
5445+ "reason": "review_requested",
5446+ "severity": "warning",
5447+ "title": "ada asked you to review flagon-io/hello#14",
5448+ "body": "Add a greeting to the README",
5449+ "event": "pull.review_requested",
5450+ "repo": "flagon-io/hello",
5451+ "workspace": "flagon-io",
5452+ "subject": "pull",
5453+ "number": 14,
5454+ "url": "/flagon-io/hello/pull/14",
5455+ "actor": "ada",
5456+ "count": 3,
5457+ "created_at": "2026-10-06T15:02:11.000Z",
5458+ "updated_at": "2026-10-07T09:41:30.000Z",
5459+ "read_at": "2026-10-07T10:03:00.000Z",
5460+ "done_at": null,
5461+ "saved": false,
5462+ "snoozed_until": null,
5463+ "activity": [
5464+ {
5465+ "reason": "review_requested",
5466+ "severity": "warning",
5467+ "title": "ada asked you to review flagon-io/hello#14",
5468+ "body": "Add a greeting to the README",
5469+ "event": "pull.review_requested",
5470+ "actor": "ada",
5471+ "created_at": "2026-10-07T09:41:30.000Z"
5472+ },
5473+ {
5474+ "reason": "comment",
5475+ "severity": "info",
5476+ "title": "ada commented on flagon-io/hello#14",
5477+ "body": "Pushed the fix for the heading.",
5478+ "event": "comment.created",
5479+ "actor": "ada",
5480+ "created_at": "2026-10-06T18:20:02.000Z"
5481+ },
5482+ {
5483+ "reason": "comment",
5484+ "severity": "info",
5485+ "title": "g1t commented on flagon-io/hello#14",
5486+ "body": "The heading level is off by one.",
5487+ "event": "comment.created",
5488+ "actor": "g1t",
5489+ "created_at": "2026-10-06T15:02:11.000Z"
5490+ }
5491+ ],
5492+ "subscription": {
5493+ "subscribed": true,
5494+ "ignored": false,
5495+ "reason": "review_requested",
5496+ "repo": "flagon-io/hello",
5497+ "number": 14,
5498+ "updated_at": null
5499+ }
5500+ }
5501+ },
5502+ "get_thread_subscription": {
5503+ "params": {
5504+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5505+ },
5506+ "response": {
5507+ "subscribed": true,
5508+ "ignored": false,
5509+ "reason": "review_requested",
5510+ "repo": "flagon-io/hello",
5511+ "number": 14,
5512+ "updated_at": null
5513+ }
5514+ },
5515+ "set_thread_subscription": {
5516+ "params": {
5517+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5518+ },
5519+ "request": {
5520+ "ignored": true
5521+ },
5522+ "response": {
5523+ "subscribed": false,
5524+ "ignored": true,
5525+ "reason": null,
5526+ "repo": "flagon-io/hello",
5527+ "number": 14,
5528+ "updated_at": "2026-10-07T10:04:00.000Z"
5529+ },
5530+ "notes": "| Body | Then |\n| --- | --- |\n| `{}` or `{\"subscribed\": true}` | You hear of what happens on it |\n| `{\"subscribed\": false}` | You hear only of what is asked of you |\n| `{\"ignored\": true}` | You hear of nothing on it, not even a mention |"
5531+ },
5532+ "delete_thread_subscription": {
5533+ "params": {
5534+ "id": "ntf_01kp7m2q3r4s5t6v7w8x9y0z1a"
5535+ },
5536+ "response": {
5537+ "subscribed": false,
5538+ "ignored": false,
5539+ "reason": null,
5540+ "repo": "flagon-io/hello",
5541+ "number": 14,
5542+ "updated_at": "2026-10-07T10:04:00.000Z"
5543+ }
5544+ },
5545+ "get_issue_subscription": {
5546+ "params": {
5547+ "owner": "flagon-io",
5548+ "name": "hello",
5549+ "number": 14
5550+ },
5551+ "response": {
5552+ "subscribed": true,
5553+ "ignored": false,
5554+ "reason": "author",
5555+ "repo": null,
5556+ "number": 14,
5557+ "updated_at": null
5558+ }
5559+ },
5560+ "set_issue_subscription": {
5561+ "params": {
5562+ "owner": "flagon-io",
5563+ "name": "hello",
5564+ "number": 14
5565+ },
5566+ "request": {
5567+ "subscribed": true
5568+ },
5569+ "response": {
5570+ "subscribed": true,
5571+ "ignored": false,
5572+ "reason": "manual",
5573+ "repo": null,
5574+ "number": 14,
5575+ "updated_at": "2026-10-07T10:05:00.000Z"
5576+ }
5577+ },
5578+ "delete_issue_subscription": {
5579+ "params": {
5580+ "owner": "flagon-io",
5581+ "name": "hello",
5582+ "number": 14
5583+ },
5584+ "response": {
5585+ "subscribed": false,
5586+ "ignored": false,
5587+ "reason": null,
5588+ "repo": null,
5589+ "number": 14,
5590+ "updated_at": "2026-10-07T10:05:30.000Z"
5591+ }
5592+ },
5593+ "get_repo_subscription": {
5594+ "params": {
5595+ "owner": "flagon-io",
5596+ "name": "hello"
5597+ },
5598+ "response": {
5599+ "repo": "flagon-io/hello",
5600+ "level": "participating",
5601+ "events": [],
5602+ "subscribed": false,
5603+ "ignored": false,
5604+ "updated_at": null
5605+ }
5606+ },
5607+ "set_repo_subscription": {
5608+ "params": {
5609+ "owner": "flagon-io",
5610+ "name": "hello"
5611+ },
5612+ "request": {
5613+ "level": "custom",
5614+ "events": [
5615+ "pulls",
5616+ "deployments"
5617+ ]
5618+ },
5619+ "response": {
5620+ "repo": "flagon-io/hello",
5621+ "level": "custom",
5622+ "events": [
5623+ "pulls",
5624+ "deployments"
5625+ ],
5626+ "subscribed": true,
5627+ "ignored": false,
5628+ "updated_at": "2026-10-07T10:06:00.000Z"
5629+ },
5630+ "notes": "| `level` | You hear of |\n| --- | --- |\n| `participating` | What you take part in, or are mentioned in (the default) |\n| `all` | Every issue and pull request opened, commented on, closed or merged, and every deployment |\n| `custom` | What you take part in, and the kinds in `events`: `issues`, `pulls`, `deployments`, `security` |\n| `ignore` | Nothing, not even a mention |\n\nInstead of `level`, `{\"subscribed\": true}` is `all`, `{\"subscribed\": false}` is `participating` and `{\"ignored\": true}` is `ignore`."
5631+ },
5632+ "delete_repo_subscription": {
5633+ "params": {
5634+ "owner": "flagon-io",
5635+ "name": "hello"
5636+ },
5637+ "response": {
5638+ "repo": "flagon-io/hello",
5639+ "level": "participating",
5640+ "events": [],
5641+ "subscribed": false,
5642+ "ignored": false,
5643+ "updated_at": null
5644+ }
5645+ },
5646+ "list_watched_repos": {
5647+ "response": [
5648+ {
5649+ "repo": "flagon-io/hello",
5650+ "level": "all",
5651+ "events": [],
5652+ "subscribed": true,
5653+ "ignored": false,
5654+ "updated_at": "2026-10-07T10:00:00.000Z"
5655+ },
5656+ {
5657+ "repo": "flagon-io/docs",
5658+ "level": "ignore",
5659+ "events": [],
5660+ "subscribed": false,
5661+ "ignored": true,
5662+ "updated_at": "2026-10-05T14:30:00.000Z"
5663+ }
5664+ ]
5665+ },
5666+ "get_usage": {
5667+ "params": {
5668+ "workspace": "flagon-io"
5669+ },
5670+ "query": {
5671+ "from": "2026-10-01",
5672+ "until": "2026-10-07",
5673+ "group_by": "project"
5674+ },
5675+ "response": {
5676+ "from": "2026-10-01",
5677+ "until": "2026-10-07",
5678+ "totals": {
5679+ "price_micros": 48210000,
5680+ "discount_micros": 0,
5681+ "included_micros": 20000000,
5682+ "credits_micros": 18000000,
5683+ "charged_micros": 10210000,
5684+ "pending_micros": 1340000,
5685+ "cost_micros": 40100000
5686+ },
5687+ "days": [
5688+ {
5689+ "day": "2026-10-06",
5690+ "product": "agent",
5691+ "micros": 12400000
5692+ },
5693+ {
5694+ "day": "2026-10-06",
5695+ "product": "sandboxes",
5696+ "micros": 2100000
5697+ },
5698+ {
5699+ "day": "2026-10-07",
5700+ "product": "agent",
5701+ "micros": 9800000
5702+ }
5703+ ],
5704+ "products": [
5705+ {
5706+ "key": "agent",
5707+ "label": "Agent",
5708+ "micros": 41000000,
5709+ "meters": [
5710+ {
5711+ "key": "agent_models",
5712+ "label": "Models",
5713+ "product": "agent",
5714+ "unit": "tokens",
5715+ "quantity": 9120000,
5716+ "micros": 41000000,
5717+ "pending_micros": 0,
5718+ "daily": [
5719+ 3100000,
5720+ 5200000,
5721+ 4400000,
5722+ 6000000,
5723+ 0,
5724+ 12400000,
5725+ 9800000
5726+ ],
5727+ "allowance": null,
5728+ "by_project": [
5729+ {
5730+ "project": "flagon-io/g1t",
5731+ "micros": 36000000,
5732+ "quantity": 8010000
5733+ },
5734+ {
5735+ "project": "flagon-io/hello",
5736+ "micros": 5000000,
5737+ "quantity": 1110000
5738+ }
5739+ ]
5740+ }
5741+ ],
5742+ "features": [
5743+ {
5744+ "key": "runs",
5745+ "label": "Runs",
5746+ "micros": 33000000,
5747+ "count": 14
5748+ },
5749+ {
5750+ "key": "reviews",
5751+ "label": "Reviews",
5752+ "micros": 8000000,
5753+ "count": 9
5754+ }
5755+ ]
5756+ },
5757+ {
5758+ "key": "sandboxes",
5759+ "label": "Sandboxes",
5760+ "micros": 7210000,
5761+ "meters": [
5762+ {
5763+ "key": "sandbox",
5764+ "label": "Sandbox time",
5765+ "product": "sandboxes",
5766+ "unit": "seconds",
5767+ "quantity": 41300,
5768+ "micros": 7210000,
5769+ "pending_micros": 0,
5770+ "daily": [
5771+ 900000,
5772+ 1200000,
5773+ 800000,
5774+ 1100000,
5775+ 0,
5776+ 2100000,
5777+ 1110000
5778+ ],
5779+ "allowance": {
5780+ "used": 41300,
5781+ "of": 108000,
5782+ "unit": "seconds"
5783+ },
5784+ "by_project": [
5785+ {
5786+ "project": "flagon-io/g1t",
5787+ "micros": 7210000,
5788+ "quantity": 41300
5789+ }
5790+ ]
5791+ }
5792+ ],
5793+ "features": []
5794+ }
5795+ ],
5796+ "projects": [
5797+ "flagon-io/g1t",
5798+ "flagon-io/hello"
5799+ ],
5800+ "models": [
5801+ {
5802+ "model": "claude-sonnet-5-5",
5803+ "input": 310000,
5804+ "output": 420000,
5805+ "cache_read": 7800000,
5806+ "cache_write": 590000
5807+ }
5808+ ],
5809+ "included": {
5810+ "used": 20,
5811+ "of": 20,
5812+ "unit": "dollars"
5813+ },
5814+ "discount_percent": null,
5815+ "ai_credit_micros": 62000000,
5816+ "credit_micros": 0,
5817+ "trial_micros": null,
5818+ "plan": "pro",
5819+ "free": false,
5820+ "group_by": "project",
5821+ "groups": [
5822+ {
5823+ "key": "flagon-io/g1t",
5824+ "micros": 43210000
5825+ },
5826+ {
5827+ "key": "flagon-io/hello",
5828+ "micros": 5000000
5829+ }
5830+ ]
5831+ },
5832+ "notes": "Every product family is listed, in order, even with nothing used; this example shows two. `daily` has one amount for each day of the range, oldest first. `projects` and `products` take several values separated by commas: `?products=agent,sandboxes`. A range of more than 400 days, or one that ends before it starts, is refused with `invalid`."
5833+ },
5834+ "get_budget": {
5835+ "params": {
5836+ "workspace": "flagon-io"
5837+ },
5838+ "response": {
5839+ "workspace": "flagon-io",
5840+ "amount_micros": 500000000,
5841+ "automatic": false,
5842+ "spent_micros": 132450000,
5843+ "max_amount_micros": 2000000000,
5844+ "alerts": [
5845+ 50,
5846+ 75,
5847+ 90,
5848+ 100
5849+ ],
5850+ "pause_at_limit": true,
5851+ "webhook": "https://ops.example.com/g1t/budget",
5852+ "state": "ok",
5853+ "message": null
5854+ },
5855+ "notes": "All amounts are whole millionths of a dollar: 500000000 is $500. `max_amount_micros` is null for g1t's own workspaces, which have no ceiling. When `state` is `stopped`, new sandboxes, builds and app requests wait until the limit is raised or the month closes."
5856+ },
5857+ "set_budget": {
5858+ "params": {
5859+ "workspace": "flagon-io"
5860+ },
5861+ "request": {
5862+ "amount_micros": 500000000,
5863+ "alerts": [
5864+ 50,
5865+ 75,
5866+ 90,
5867+ 100
5868+ ],
5869+ "webhook": "https://ops.example.com/g1t/budget"
5870+ },
5871+ "response": {
5872+ "workspace": "flagon-io",
5873+ "amount_micros": 500000000,
5874+ "automatic": false,
5875+ "spent_micros": 132450000,
5876+ "max_amount_micros": 2000000000,
5877+ "alerts": [
5878+ 50,
5879+ 75,
5880+ 90,
5881+ 100
5882+ ],
5883+ "pause_at_limit": true,
5884+ "webhook": "https://ops.example.com/g1t/budget",
5885+ "state": "ok",
5886+ "message": null
5887+ },
5888+ "notes": "Fields left out keep their value. A limit above `max_amount_micros` is refused with `invalid`. Called by anyone but an owner signed in as a person, or by a workspace's own token or one of g1t's agents, it is refused with `forbidden`. Each alert is sent once a month, to the owners by email and, with `webhook`, as a JSON POST."
5889+ },
5890+ "get_ai_credit": {
5891+ "params": {
5892+ "workspace": "flagon-io"
5893+ },
5894+ "response": {
5895+ "balance_micros": 62000000,
5896+ "purchased_micros": 50000000,
5897+ "given_micros": 12000000,
5898+ "grants": [
5899+ {
5900+ "id": "crd_01kkr2m4c8f1t7qh3d6n9w5p0x",
5901+ "workspace": "flagon-io",
5902+ "kind": "purchase",
5903+ "amount_micros": 50000000,
5904+ "used_micros": 0,
5905+ "left_micros": 50000000,
5906+ "note": "AI credit bought",
5907+ "refund_for": null,
5908+ "refund_day": null,
5909+ "expires_at": "2027-10-02T00:00:00.000Z",
5910+ "created_by": "ana",
5911+ "created_at": "2026-10-02T16:20:00.000Z",
5912+ "state": "open",
5913+ "closed_at": null,
5914+ "closed_note": null,
5915+ "closed_by": null
5916+ }
5917+ ],
5918+ "free_via_discount": false,
5919+ "postpaid": false,
5920+ "blocked": false,
5921+ "can_buy": true,
5922+ "presets_cents": [
5923+ 2500,
5924+ 5000,
5925+ 10000,
5926+ 25000
5927+ ],
5928+ "min_cents": 1000,
5929+ "max_cents": 100000,
5930+ "card_fee": {
5931+ "on": true,
5932+ "percent_micros": 29000,
5933+ "fixed_cents": 30
5934+ },
5935+ "reload": {
5936+ "enabled": false,
5937+ "threshold_micros": 10000000,
5938+ "target_micros": 50000000,
5939+ "monthly_max_micros": 200000000,
5940+ "reloaded_micros": 0,
5941+ "failed_at": null,
5942+ "error": null
5943+ },
5944+ "agent_rate_micros": 3.6,
5945+ "model_markup_percent": 10,
5946+ "gateway_markup_percent": 5,
5947+ "upgrade_credit_micros": 10000000,
5948+ "expires_days": 365
5949+ },
5950+ "notes": "`card_fee.percent_micros` is per dollar charged, in millionths: 29000 is 2.9%. `blocked` is true when the credit has run out and new runs on g1t's models wait for more; runs on a model provider the workspace connected itself never need it."
5951+ },
5952+ "buy_ai_credit": {
5953+ "params": {
5954+ "workspace": "flagon-io"
5955+ },
5956+ "request": {
5957+ "amount_cents": 5000
5958+ },
5959+ "response": {
5960+ "url": "https://checkout.example.com/c/pay/cs_test_a1b2c3"
5961+ },
5962+ "notes": "Open `url` in a browser to pay. Nothing is charged until the payment is made there; the credit then shows in get_ai_credit. An amount outside `min_cents` to `max_cents`, or not in whole dollars, is refused with `invalid`; a workspace that cannot buy credit (see `can_buy`) gets `conflict` or `payment_required`."
5963+ },
5964+ "list_invoices": {
5965+ "params": {
5966+ "workspace": "flagon-io"
5967+ },
5968+ "response": {
5969+ "invoices": [
5970+ {
5971+ "id": "in_1Q2w3E4r5T6y7U8i",
5972+ "number": "FLAGON-0004",
5973+ "status": "paid",
5974+ "total_cents": 4210,
5975+ "currency": "usd",
5976+ "created_at": "2026-10-01T00:05:00.000Z",
5977+ "description": "Usage for 2026-09",
5978+ "hosted_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i",
5979+ "pdf_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i/pdf"
5980+ }
5981+ ],
5982+ "usage_invoices": [
5983+ {
5984+ "id": "inv_01kkqz8d3c6f9t2wq5n8h1m4r7",
5985+ "workspace": "flagon-io",
5986+ "reason": "month",
5987+ "period": "2026-09",
5988+ "amount_micros": 42100000,
5989+ "status": "paid",
5990+ "hosted_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i",
5991+ "pdf_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i/pdf",
5992+ "lines": [
5993+ {
5994+ "description": "Agent: models",
5995+ "amount_micros": 35900000
5996+ },
5997+ {
5998+ "description": "Sandbox time",
5999+ "amount_micros": 6200000
6000+ }
6001+ ],
6002+ "created_at": "2026-10-01T00:05:00.000Z"
6003+ },
6004+ {
6005+ "id": "inv_01kkqz8d3c6f9t2wq5n8h1m4r7",
6006+ "workspace": "flagon-io",
6007+ "reason": "month",
6008+ "period": "2026-09",
6009+ "amount_micros": 42100000,
6010+ "status": "paid",
6011+ "hosted_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i",
6012+ "pdf_url": "https://invoice.example.com/i/acct_1/in_1Q2w3E4r5T6y7U8i/pdf",
6013+ "lines": [
6014+ {
6015+ "description": "Agent: models",
6016+ "amount_micros": 35900000
6017+ },
6018+ {
6019+ "description": "Sandbox time",
6020+ "amount_micros": 6200000
6021+ }
6022+ ],
6023+ "created_at": "2026-10-01T00:05:00.000Z",
6024+ "fee_micros": 1600000,
6025+ "tax_micros": 3510000
6026+ }
6027+ ],
6028+ "upcoming": {
6029+ "closes_at": "2026-11-01T00:00:00.000Z",
6030+ "subscriptions_micros": 20000000,
6031+ "usage_micros": 10210000,
6032+ "total_micros": 30210000
6033+ },
6034+ "unavailable": null
6035+ },
6036+ "notes": "`invoices` are in cents (`total_cents`); `usage_invoices` and `upcoming` in millionths of a dollar. A usage invoice's `reason` is `month` (the month closed) or `threshold` (charged near the limit), and its `status` `paid`, `open`, `failed` or `void`. An invoice's `status` is `paid`, `open`, `void`, `uncollectible` or `draft`."
6037+ },
6038+ "get_billing_details": {
6039+ "params": {
6040+ "workspace": "flagon-io"
6041+ },
6042+ "response": {
6043+ "customer": true,
6044+ "email": "billing@flagon.example.com",
6045+ "name": "Flagon, Inc.",
6046+ "address": {
6047+ "line1": "100 Market Street",
6048+ "line2": "",
6049+ "city": "San Francisco",
6050+ "state": "CA",
6051+ "postal_code": "94105",
6052+ "country": "US"
6053+ },
6054+ "tax_id_type": "us_ein",
6055+ "tax_id": "12-3456789",
6056+ "po_number": null,
6057+ "language": "en",
6058+ "payment_method": {
6059+ "kind": "card",
6060+ "brand": "visa",
6061+ "last4": "4242",
6062+ "exp_month": 12,
6063+ "exp_year": 2028
6064+ },
6065+ "tax_location": true,
6066+ "tax_address_needed_at": null,
6067+ "tax_id_status": "unavailable",
6068+ "tax_exempt": "none"
6069+ },
6070+ "notes": "Owners change these on the workspace's billing page. `payment_method` is null until a card or other way to pay is saved. Tax is worked out from the address: `tax_location` is false until it has at least a country (and in the US a ZIP code), and `tax_address_needed_at` is set while a charge waits for one."
6071+ },
6072+ "list_pinned_projects": {
6073+ "params": {
6074+ "workspace": "flagon-io"
6075+ },
6076+ "response": [
6077+ {
6078+ "position": 0,
6079+ "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6080+ "workspace": "flagon-io",
6081+ "slug": "g1t",
6082+ "name": "g1t",
6083+ "description": null,
6084+ "private": false,
6085+ "archived": false,
6086+ "kind": "app",
6087+ "url": "https://g1t.sh/flagon-io/g1t",
6088+ "pushed_at": "2026-10-07T10:00:00.000Z",
6089+ "updated_at": "2026-10-01T09:12:00.000Z"
6090+ },
6091+ {
6092+ "position": 1,
6093+ "id": "prj_01kkq0c4d9h2w7rn5f8t3k6p2z",
6094+ "workspace": "flagon-io",
6095+ "slug": "lab-api",
6096+ "name": "lab-api",
6097+ "description": null,
6098+ "private": true,
6099+ "archived": false,
6100+ "kind": "app",
6101+ "url": "https://g1t.sh/flagon-io/lab-api",
6102+ "pushed_at": "2026-10-06T18:40:00.000Z",
6103+ "updated_at": "2026-10-01T09:12:00.000Z"
6104+ },
6105+ {
6106+ "position": 2,
6107+ "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6108+ "workspace": "flagon-io",
6109+ "slug": "hello",
6110+ "name": "hello",
6111+ "description": "Greets people from the command line.",
6112+ "private": false,
6113+ "archived": false,
6114+ "kind": "library",
6115+ "url": "https://g1t.sh/flagon-io/hello",
6116+ "pushed_at": null,
6117+ "updated_at": "2026-10-01T09:12:00.000Z"
6118+ }
6119+ ],
6120+ "notes": "In your order: `position` 0 first. The sidebar shows these, then the projects you opened last. `pushed_at` is null until the project's repository is pushed to."
6121+ },
6122+ "pin_project": {
6123+ "params": {
6124+ "workspace": "flagon-io",
6125+ "project": "hello"
6126+ },
6127+ "request": {
6128+ "position": 0
6129+ },
6130+ "response": [
6131+ {
6132+ "position": 0,
6133+ "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6134+ "workspace": "flagon-io",
6135+ "slug": "hello",
6136+ "name": "hello",
6137+ "description": "Greets people from the command line.",
6138+ "private": false,
6139+ "archived": false,
6140+ "kind": "library",
6141+ "url": "https://g1t.sh/flagon-io/hello",
6142+ "pushed_at": null,
6143+ "updated_at": "2026-10-01T09:12:00.000Z"
6144+ },
6145+ {
6146+ "position": 1,
6147+ "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6148+ "workspace": "flagon-io",
6149+ "slug": "g1t",
6150+ "name": "g1t",
6151+ "description": null,
6152+ "private": false,
6153+ "archived": false,
6154+ "kind": "app",
6155+ "url": "https://g1t.sh/flagon-io/g1t",
6156+ "pushed_at": "2026-10-07T10:00:00.000Z",
6157+ "updated_at": "2026-10-01T09:12:00.000Z"
6158+ },
6159+ {
6160+ "position": 2,
6161+ "id": "prj_01kkq0c4d9h2w7rn5f8t3k6p2z",
6162+ "workspace": "flagon-io",
6163+ "slug": "lab-api",
6164+ "name": "lab-api",
6165+ "description": null,
6166+ "private": true,
6167+ "archived": false,
6168+ "kind": "app",
6169+ "url": "https://g1t.sh/flagon-io/lab-api",
6170+ "pushed_at": "2026-10-06T18:40:00.000Z",
6171+ "updated_at": "2026-10-01T09:12:00.000Z"
6172+ }
6173+ ],
6174+ "notes": "A ninth pin in a workspace is refused with `409 conflict`: unpin one first."
6175+ },
6176+ "unpin_project": {
6177+ "params": {
6178+ "workspace": "flagon-io",
6179+ "project": "lab-api"
6180+ },
6181+ "response": [
6182+ {
6183+ "position": 0,
6184+ "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6185+ "workspace": "flagon-io",
6186+ "slug": "g1t",
6187+ "name": "g1t",
6188+ "description": null,
6189+ "private": false,
6190+ "archived": false,
6191+ "kind": "app",
6192+ "url": "https://g1t.sh/flagon-io/g1t",
6193+ "pushed_at": "2026-10-07T10:00:00.000Z",
6194+ "updated_at": "2026-10-01T09:12:00.000Z"
6195+ },
6196+ {
6197+ "position": 1,
6198+ "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6199+ "workspace": "flagon-io",
6200+ "slug": "hello",
6201+ "name": "hello",
6202+ "description": "Greets people from the command line.",
6203+ "private": false,
6204+ "archived": false,
6205+ "kind": "library",
6206+ "url": "https://g1t.sh/flagon-io/hello",
6207+ "pushed_at": null,
6208+ "updated_at": "2026-10-01T09:12:00.000Z"
6209+ }
6210+ ]
6211+ },
6212+ "reorder_pinned_projects": {
6213+ "params": {
6214+ "workspace": "flagon-io"
6215+ },
6216+ "request": {
6217+ "projects": [
6218+ "lab-api",
6219+ "g1t",
6220+ "hello"
6221+ ]
6222+ },
6223+ "response": [
6224+ {
6225+ "position": 0,
6226+ "id": "prj_01kkq0c4d9h2w7rn5f8t3k6p2z",
6227+ "workspace": "flagon-io",
6228+ "slug": "lab-api",
6229+ "name": "lab-api",
6230+ "description": null,
6231+ "private": true,
6232+ "archived": false,
6233+ "kind": "app",
6234+ "url": "https://g1t.sh/flagon-io/lab-api",
6235+ "pushed_at": "2026-10-06T18:40:00.000Z",
6236+ "updated_at": "2026-10-01T09:12:00.000Z"
6237+ },
6238+ {
6239+ "position": 1,
6240+ "id": "prj_01kkp3m8w2f6t9qh4c7d1r5n0x",
6241+ "workspace": "flagon-io",
6242+ "slug": "g1t",
6243+ "name": "g1t",
6244+ "description": null,
6245+ "private": false,
6246+ "archived": false,
6247+ "kind": "app",
6248+ "url": "https://g1t.sh/flagon-io/g1t",
6249+ "pushed_at": "2026-10-07T10:00:00.000Z",
6250+ "updated_at": "2026-10-01T09:12:00.000Z"
6251+ },
6252+ {
6253+ "position": 2,
6254+ "id": "prj_01kkp3n2a7e5v8sk3b6g9j4m1y",
6255+ "workspace": "flagon-io",
6256+ "slug": "hello",
6257+ "name": "hello",
6258+ "description": "Greets people from the command line.",
6259+ "private": false,
6260+ "archived": false,
6261+ "kind": "library",
6262+ "url": "https://g1t.sh/flagon-io/hello",
6263+ "pushed_at": null,
6264+ "updated_at": "2026-10-01T09:12:00.000Z"
6265+ }
6266+ ],
6267+ "notes": "Name every pinned project once; anything else is refused with `422 invalid`."
6268+ },
6269+ "list_secret_scanning_alerts": {
6270+ "params": {
6271+ "owner": "flagon-io",
6272+ "name": "hello"
6273+ },
6274+ "query": {
6275+ "state": "open"
6276+ },
6277+ "response": [
6278+ {
6279+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6280+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6281+ "kind": "github_token",
6282+ "label": "a GitHub token",
6283+ "path": "scripts/release.sh",
6284+ "line": 12,
6285+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6286+ "preview": "ghp_X7…",
6287+ "status": "open",
6288+ "source": "push",
6289+ "found_by": "syntaqx",
6290+ "found_at": "2026-10-06T09:14:02.118Z",
6291+ "decided_by": null,
6292+ "reason": null,
6293+ "decided_at": null,
6294+ "dismissed_reason": null,
6295+ "test_value": null,
6296+ "state": "open",
6297+ "validity": "active",
6298+ "validity_checked_at": "2026-10-06T09:20:41.502Z",
6299+ "bypass": {
6300+ "reason": "will_fix_later",
6301+ "comment": "Rotating it this afternoon.",
6302+ "by": "syntaqx",
6303+ "at": "2026-10-06T09:14:02.118Z",
6304+ "approved_by": null
6305+ },
6306+ "pattern_id": null,
6307+ "pattern_name": null,
6308+ "locations": 1
6309+ }
6310+ ],
6311+ "notes": "| Filter | Values |\n| --- | --- |\n| `state` | `open` (in the history, or blocked at a push), `dismissed`, `fixed` |\n| `secret_type` | `aws_access_key`, `github_token`, `custom_pattern`, … |\n| `validity` | `active`, `inactive`, `unknown`, `unsupported` |\n| `bypassed` | `true` or `false` |\n\nThe secret itself is never returned: `preview` is enough to recognise it. `status` says where it stands: `open`, `blocked` (stopped at a push, never landed), `allowed` or `resolved`."
6312+ },
6313+ "list_secret_scanning_alerts_for_workspace": {
6314+ "params": {
6315+ "workspace": "flagon-io"
6316+ },
6317+ "query": {
6318+ "state": "open"
6319+ },
6320+ "response": [
6321+ {
6322+ "repo": "hello",
6323+ "secret": {
6324+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6325+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6326+ "kind": "github_token",
6327+ "label": "a GitHub token",
6328+ "path": "scripts/release.sh",
6329+ "line": 12,
6330+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6331+ "preview": "ghp_X7…",
6332+ "status": "open",
6333+ "source": "push",
6334+ "found_by": "syntaqx",
6335+ "found_at": "2026-10-06T09:14:02.118Z",
6336+ "decided_by": null,
6337+ "reason": null,
6338+ "decided_at": null,
6339+ "dismissed_reason": null,
6340+ "test_value": null,
6341+ "state": "open",
6342+ "validity": "active",
6343+ "validity_checked_at": "2026-10-06T09:20:41.502Z",
6344+ "bypass": {
6345+ "reason": "will_fix_later",
6346+ "comment": "Rotating it this afternoon.",
6347+ "by": "syntaqx",
6348+ "at": "2026-10-06T09:14:02.118Z",
6349+ "approved_by": null
6350+ },
6351+ "pattern_id": null,
6352+ "pattern_name": null,
6353+ "locations": 1
6354+ }
6355+ }
6356+ ],
6357+ "notes": "Every repository whose findings you may see, each alert with its repository's name."
6358+ },
6359+ "get_secret_scanning_alert": {
6360+ "params": {
6361+ "owner": "flagon-io",
6362+ "name": "hello",
6363+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6364+ },
6365+ "response": {
6366+ "secret": {
6367+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6368+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6369+ "kind": "github_token",
6370+ "label": "a GitHub token",
6371+ "path": "scripts/release.sh",
6372+ "line": 12,
6373+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6374+ "preview": "ghp_X7…",
6375+ "status": "blocked",
6376+ "source": "push",
6377+ "found_by": "syntaqx",
6378+ "found_at": "2026-10-06T09:14:02.118Z",
6379+ "decided_by": null,
6380+ "reason": null,
6381+ "decided_at": null,
6382+ "dismissed_reason": null,
6383+ "test_value": null,
6384+ "state": "open",
6385+ "validity": null,
6386+ "validity_checked_at": null,
6387+ "bypass": null,
6388+ "pattern_id": null,
6389+ "pattern_name": null,
6390+ "locations": 1
6391+ },
6392+ "locations": [
6393+ {
6394+ "path": "scripts/release.sh",
6395+ "line": 12,
6396+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6397+ "source": "push",
6398+ "found_at": "2026-10-06T09:14:02.118Z"
6399+ }
6400+ ],
6401+ "activity": [],
6402+ "requests": [],
6403+ "checkable": true,
6404+ "can_bypass": true,
6405+ "can_request_bypass": false
6406+ }
6407+ },
6408+ "update_secret_scanning_alert": {
6409+ "params": {
6410+ "owner": "flagon-io",
6411+ "name": "hello",
6412+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6413+ },
6414+ "request": {
6415+ "state": "dismissed",
6416+ "reason": "revoked",
6417+ "comment": "Rotated in the issuer's settings."
6418+ },
6419+ "response": {
6420+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6421+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6422+ "kind": "github_token",
6423+ "label": "a GitHub token",
6424+ "path": "scripts/release.sh",
6425+ "line": 12,
6426+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6427+ "preview": "ghp_X7…",
6428+ "status": "resolved",
6429+ "source": "push",
6430+ "found_by": "syntaqx",
6431+ "found_at": "2026-10-06T09:14:02.118Z",
6432+ "decided_by": "syntaqx",
6433+ "reason": "Rotated in the issuer's settings.",
6434+ "decided_at": "2026-10-06T09:20:41.502Z",
6435+ "dismissed_reason": "revoked",
6436+ "test_value": null,
6437+ "state": "fixed",
6438+ "validity": "active",
6439+ "validity_checked_at": "2026-10-06T09:20:41.502Z",
6440+ "bypass": {
6441+ "reason": "will_fix_later",
6442+ "comment": "Rotating it this afternoon.",
6443+ "by": "syntaqx",
6444+ "at": "2026-10-06T09:14:02.118Z",
6445+ "approved_by": null
6446+ },
6447+ "pattern_id": null,
6448+ "pattern_name": null,
6449+ "locations": 1
6450+ },
6451+ "notes": "Takes the Admin role: a dismissed secret is let through push protection, unless it was `revoked`, which marks it fixed. `state` `open` reopens it."
6452+ },
6453+ "list_secret_scanning_locations": {
6454+ "params": {
6455+ "owner": "flagon-io",
6456+ "name": "hello",
6457+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6458+ },
6459+ "response": [
6460+ {
6461+ "path": "scripts/release.sh",
6462+ "line": 12,
6463+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6464+ "source": "push",
6465+ "found_at": "2026-10-06T09:14:02.118Z"
6466+ }
6467+ ]
6468+ },
6469+ "bypass_push_protection": {
6470+ "params": {
6471+ "owner": "flagon-io",
6472+ "name": "hello",
6473+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6474+ },
6475+ "request": {
6476+ "reason": "will_fix_later",
6477+ "comment": "Rotating it this afternoon."
6478+ },
6479+ "response": {
6480+ "secret": {
6481+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6482+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6483+ "kind": "github_token",
6484+ "label": "a GitHub token",
6485+ "path": "scripts/release.sh",
6486+ "line": 12,
6487+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6488+ "preview": "ghp_X7…",
6489+ "status": "open",
6490+ "source": "push",
6491+ "found_by": "syntaqx",
6492+ "found_at": "2026-10-06T09:14:02.118Z",
6493+ "decided_by": null,
6494+ "reason": null,
6495+ "decided_at": null,
6496+ "dismissed_reason": null,
6497+ "test_value": null,
6498+ "state": "open",
6499+ "validity": null,
6500+ "validity_checked_at": null,
6501+ "bypass": {
6502+ "reason": "will_fix_later",
6503+ "comment": "Rotating it this afternoon.",
6504+ "by": "syntaqx",
6505+ "at": "2026-10-06T09:14:02.118Z",
6506+ "approved_by": null
6507+ },
6508+ "pattern_id": null,
6509+ "pattern_name": null,
6510+ "locations": 1
6511+ },
6512+ "request": null
6513+ },
6514+ "notes": "| Reason | The alert |\n| --- | --- |\n| `false_positive` | Closed as a false positive |\n| `used_in_tests` | Closed as used in tests |\n| `will_fix_later` | Stays open, to be rotated |\n\nWith delegated bypass on, a call from someone who does not review bypasses makes a request instead: `request` is set and the secret is still blocked until an owner or admin approves it. Push again once it is bypassed."
6515+ },
6516+ "check_secret_validity": {
6517+ "params": {
6518+ "owner": "flagon-io",
6519+ "name": "hello",
6520+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p"
6521+ },
6522+ "response": {
6523+ "id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6524+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6525+ "kind": "github_token",
6526+ "label": "a GitHub token",
6527+ "path": "scripts/release.sh",
6528+ "line": 12,
6529+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6530+ "preview": "ghp_X7…",
6531+ "status": "open",
6532+ "source": "push",
6533+ "found_by": "syntaqx",
6534+ "found_at": "2026-10-06T09:14:02.118Z",
6535+ "decided_by": null,
6536+ "reason": null,
6537+ "decided_at": null,
6538+ "dismissed_reason": null,
6539+ "test_value": null,
6540+ "state": "open",
6541+ "validity": "active",
6542+ "validity_checked_at": "2026-10-06T09:20:41.502Z",
6543+ "bypass": {
6544+ "reason": "will_fix_later",
6545+ "comment": "Rotating it this afternoon.",
6546+ "by": "syntaqx",
6547+ "at": "2026-10-06T09:14:02.118Z",
6548+ "approved_by": null
6549+ },
6550+ "pattern_id": null,
6551+ "pattern_name": null,
6552+ "locations": 1
6553+ },
6554+ "notes": "Made for GitHub, GitLab, Stripe, Slack, npm, OpenAI, Anthropic and SendGrid tokens, with the issuer's own read-only call. Other formats answer `unsupported`; a secret that never landed answers `unknown`."
6555+ },
6556+ "list_bypass_requests": {
6557+ "params": {
6558+ "workspace": "flagon-io"
6559+ },
6560+ "query": {
6561+ "state": "pending"
6562+ },
6563+ "response": [
6564+ {
6565+ "id": "byp_01kq2n8e5f6g7h8j9k0m1n2p3q",
6566+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6567+ "workspace": "flagon-io",
6568+ "repo": "hello",
6569+ "secret_id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6570+ "label": "a GitHub token",
6571+ "path": "scripts/release.sh",
6572+ "line": 12,
6573+ "preview": "ghp_X7…",
6574+ "requester": "ana",
6575+ "reason": "used_in_tests",
6576+ "comment": "A token from the test fixtures, never issued.",
6577+ "state": "pending",
6578+ "reviewer": null,
6579+ "review_comment": null,
6580+ "created_at": "2026-10-06T09:14:02.118Z",
6581+ "reviewed_at": null
6582+ }
6583+ ]
6584+ },
6585+ "review_bypass_request": {
6586+ "params": {
6587+ "workspace": "flagon-io",
6588+ "id": "byp_01kq2n8e5f6g7h8j9k0m1n2p3q"
6589+ },
6590+ "request": {
6591+ "decision": "approve",
6592+ "comment": "A fixture."
6593+ },
6594+ "response": {
6595+ "id": "byp_01kq2n8e5f6g7h8j9k0m1n2p3q",
6596+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6597+ "workspace": "flagon-io",
6598+ "repo": "hello",
6599+ "secret_id": "sec_01kq2m7d4e5f6g7h8j9k0m1n2p",
6600+ "label": "a GitHub token",
6601+ "path": "scripts/release.sh",
6602+ "line": 12,
6603+ "preview": "ghp_X7…",
6604+ "requester": "ana",
6605+ "reason": "used_in_tests",
6606+ "comment": "A token from the test fixtures, never issued.",
6607+ "state": "approved",
6608+ "reviewer": "syntaqx",
6609+ "review_comment": "A fixture.",
6610+ "created_at": "2026-10-06T09:14:02.118Z",
6611+ "reviewed_at": "2026-10-06T09:20:41.502Z"
6612+ }
6613+ },
6614+ "list_custom_patterns": {
6615+ "params": {
6616+ "owner": "flagon-io",
6617+ "name": "hello"
6618+ },
6619+ "response": {
6620+ "patterns": [
6621+ {
6622+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6623+ "scope": "repository",
6624+ "workspace": "flagon-io",
6625+ "repo": "hello",
6626+ "name": "Acme API key",
6627+ "pattern": "acme_[a-z0-9]{32}",
6628+ "before": null,
6629+ "after": null,
6630+ "test_strings": [
6631+ "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6632+ ],
6633+ "state": "published",
6634+ "created_by": "syntaqx",
6635+ "created_at": "2026-10-06T09:14:02.118Z",
6636+ "updated_by": "syntaqx",
6637+ "updated_at": "2026-10-06T09:14:02.118Z",
6638+ "open_alerts": 0
6639+ }
6640+ ],
6641+ "entitled": true
6642+ },
6643+ "notes": "A repository's list includes its workspace's patterns, with `scope` `workspace`. `entitled` says whether they run here: always on a public repository, and on a private one with the Security and quality activation."
6644+ },
6645+ "list_custom_patterns_for_workspace": {
6646+ "params": {
6647+ "workspace": "flagon-io"
6648+ },
6649+ "response": {
6650+ "patterns": [
6651+ {
6652+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6653+ "scope": "workspace",
6654+ "workspace": "flagon-io",
6655+ "repo": null,
6656+ "name": "Acme API key",
6657+ "pattern": "acme_[a-z0-9]{32}",
6658+ "before": null,
6659+ "after": null,
6660+ "test_strings": [
6661+ "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6662+ ],
6663+ "state": "published",
6664+ "created_by": "syntaqx",
6665+ "created_at": "2026-10-06T09:14:02.118Z",
6666+ "updated_by": "syntaqx",
6667+ "updated_at": "2026-10-06T09:14:02.118Z",
6668+ "open_alerts": 0
6669+ }
6670+ ],
6671+ "entitled": true
6672+ }
6673+ },
6674+ "create_custom_pattern": {
6675+ "params": {
6676+ "owner": "flagon-io",
6677+ "name": "hello"
6678+ },
6679+ "request": {
6680+ "pattern_name": "Acme API key",
6681+ "pattern": "acme_[a-z0-9]{32}",
6682+ "test_strings": [
6683+ "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6684+ ],
6685+ "publish": true
6686+ },
6687+ "response": {
6688+ "pattern": {
6689+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6690+ "scope": "repository",
6691+ "workspace": "flagon-io",
6692+ "repo": "hello",
6693+ "name": "Acme API key",
6694+ "pattern": "acme_[a-z0-9]{32}",
6695+ "before": null,
6696+ "after": null,
6697+ "test_strings": [
6698+ "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6699+ ],
6700+ "state": "published",
6701+ "created_by": "syntaqx",
6702+ "created_at": "2026-10-06T09:14:02.118Z",
6703+ "updated_by": "syntaqx",
6704+ "updated_at": "2026-10-06T09:14:02.118Z",
6705+ "open_alerts": 0
6706+ },
6707+ "tests": [
6708+ [
6709+ 9,
6710+ 46
6711+ ]
6712+ ]
6713+ },
6714+ "notes": "`tests` gives, for each test string, where the pattern matched (start and end, in characters), or `null`. A pattern that does not compile, matches an empty string, or is too complex is refused with `422` and says why."
6715+ },
6716+ "create_custom_pattern_for_workspace": {
6717+ "params": {
6718+ "workspace": "flagon-io"
6719+ },
6720+ "request": {
6721+ "pattern_name": "Acme API key",
6722+ "pattern": "acme_[a-z0-9]{32}",
6723+ "publish": false
6724+ },
6725+ "response": {
6726+ "pattern": {
6727+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6728+ "scope": "workspace",
6729+ "workspace": "flagon-io",
6730+ "repo": null,
6731+ "name": "Acme API key",
6732+ "pattern": "acme_[a-z0-9]{32}",
6733+ "before": null,
6734+ "after": null,
6735+ "test_strings": [],
6736+ "state": "draft",
6737+ "created_by": "syntaqx",
6738+ "created_at": "2026-10-06T09:14:02.118Z",
6739+ "updated_by": "syntaqx",
6740+ "updated_at": "2026-10-06T09:14:02.118Z",
6741+ "open_alerts": 0
6742+ },
6743+ "tests": []
6744+ }
6745+ },
6746+ "update_custom_pattern": {
6747+ "params": {
6748+ "owner": "flagon-io",
6749+ "name": "hello",
6750+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6751+ },
6752+ "request": {
6753+ "pattern_name": "Acme API key",
6754+ "pattern": "acme_[a-z0-9]{32,40}",
6755+ "publish": true
6756+ },
6757+ "response": {
6758+ "pattern": {
6759+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6760+ "scope": "repository",
6761+ "workspace": "flagon-io",
6762+ "repo": "hello",
6763+ "name": "Acme API key",
6764+ "pattern": "acme_[a-z0-9]{32,40}",
6765+ "before": null,
6766+ "after": null,
6767+ "test_strings": [
6768+ "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6769+ ],
6770+ "state": "published",
6771+ "created_by": "syntaqx",
6772+ "created_at": "2026-10-06T09:14:02.118Z",
6773+ "updated_by": "syntaqx",
6774+ "updated_at": "2026-10-06T09:14:02.118Z",
6775+ "open_alerts": 0
6776+ },
6777+ "tests": [
6778+ [
6779+ 9,
6780+ 46
6781+ ]
6782+ ]
6783+ }
6784+ },
6785+ "update_custom_pattern_for_workspace": {
6786+ "params": {
6787+ "workspace": "flagon-io",
6788+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6789+ },
6790+ "request": {
6791+ "pattern_name": "Acme API key",
6792+ "pattern": "acme_[a-z0-9]{32}",
6793+ "publish": true
6794+ },
6795+ "response": {
6796+ "pattern": {
6797+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r",
6798+ "scope": "workspace",
6799+ "workspace": "flagon-io",
6800+ "repo": null,
6801+ "name": "Acme API key",
6802+ "pattern": "acme_[a-z0-9]{32}",
6803+ "before": null,
6804+ "after": null,
6805+ "test_strings": [
6806+ "ACME_KEY=acme_0123456789abcdef0123456789abcdef"
6807+ ],
6808+ "state": "published",
6809+ "created_by": "syntaqx",
6810+ "created_at": "2026-10-06T09:14:02.118Z",
6811+ "updated_by": "syntaqx",
6812+ "updated_at": "2026-10-06T09:14:02.118Z",
6813+ "open_alerts": 0
6814+ },
6815+ "tests": [
6816+ [
6817+ 9,
6818+ 46
6819+ ]
6820+ ]
6821+ }
6822+ },
6823+ "delete_custom_pattern": {
6824+ "params": {
6825+ "owner": "flagon-io",
6826+ "name": "hello",
6827+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6828+ },
6829+ "response": {
6830+ "deleted": true
6831+ }
6832+ },
6833+ "delete_custom_pattern_for_workspace": {
6834+ "params": {
6835+ "workspace": "flagon-io",
6836+ "id": "pat_01kq2p9f6g7h8j9k0m1n2p3q4r"
6837+ },
6838+ "response": {
6839+ "deleted": true
6840+ }
6841+ },
6842+ "dry_run_custom_pattern": {
6843+ "params": {
6844+ "owner": "flagon-io",
6845+ "name": "hello"
6846+ },
6847+ "request": {
6848+ "pattern": "acme_[a-z0-9]{32}"
6849+ },
6850+ "response": {
6851+ "repos": [
6852+ {
6853+ "name": "hello",
6854+ "files_scanned": 214,
6855+ "matches": [
6856+ {
6857+ "path": "config/dev.env",
6858+ "line": 3,
6859+ "preview": "ACME_KEY=acme_01••••••••••••••••••••••••"
6860+ }
6861+ ],
6862+ "truncated": false,
6863+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291"
6864+ }
6865+ ]
6866+ },
6867+ "notes": "Reads up to 2,000 files and 20 MB of the default branch, skipping what secret scanning skips. Nothing is recorded."
6868+ },
6869+ "dry_run_custom_pattern_for_workspace": {
6870+ "params": {
6871+ "workspace": "flagon-io"
6872+ },
6873+ "request": {
6874+ "pattern": "acme_[a-z0-9]{32}",
6875+ "repos": [
6876+ "hello"
6877+ ]
6878+ },
6879+ "response": {
6880+ "repos": [
6881+ {
6882+ "name": "hello",
6883+ "files_scanned": 214,
6884+ "matches": [],
6885+ "truncated": false,
6886+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291"
6887+ }
6888+ ]
6889+ }
6890+ },
6891+ "list_code_scanning_alerts": {
6892+ "params": {
6893+ "owner": "flagon-io",
6894+ "name": "hello"
6895+ },
6896+ "query": {
6897+ "state": "open",
6898+ "severity": "high"
6899+ },
6900+ "response": [
6901+ {
6902+ "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
6903+ "number": 4,
6904+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6905+ "tool": "Semgrep OSS",
6906+ "category": "Semgrep OSS",
6907+ "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
6908+ "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
6909+ "rule_description": "Detected calls to child_process from a function argument.",
6910+ "help": null,
6911+ "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
6912+ "tags": [
6913+ "security",
6914+ "CWE-78"
6915+ ],
6916+ "level": "error",
6917+ "security_severity": null,
6918+ "severity": "high",
6919+ "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
6920+ "path": "src/server.js",
6921+ "start_line": 6,
6922+ "end_line": 6,
6923+ "start_column": 3,
6924+ "end_column": 60,
6925+ "state": "open",
6926+ "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
6927+ "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6928+ "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6929+ "created_at": "2026-10-06T09:14:02.118Z",
6930+ "updated_at": "2026-10-06T09:14:02.118Z",
6931+ "fixed_at": null,
6932+ "dismissed_by": null,
6933+ "dismissed_reason": null,
6934+ "dismissed_comment": null,
6935+ "dismissed_at": null,
6936+ "issue": null
6937+ }
6938+ ],
6939+ "notes": "`severity` is the rule's security severity when it has one (from its `security-severity` score), else from the result's level: `error` high, `warning` medium, `note` low."
6940+ },
6941+ "list_code_scanning_alerts_for_workspace": {
6942+ "params": {
6943+ "workspace": "flagon-io"
6944+ },
6945+ "query": {
6946+ "state": "open"
6947+ },
6948+ "response": [
6949+ {
6950+ "repo": "hello",
6951+ "code": {
6952+ "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
6953+ "number": 4,
6954+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
6955+ "tool": "Semgrep OSS",
6956+ "category": "Semgrep OSS",
6957+ "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
6958+ "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
6959+ "rule_description": "Detected calls to child_process from a function argument.",
6960+ "help": null,
6961+ "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
6962+ "tags": [
6963+ "security",
6964+ "CWE-78"
6965+ ],
6966+ "level": "error",
6967+ "security_severity": null,
6968+ "severity": "high",
6969+ "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
6970+ "path": "src/server.js",
6971+ "start_line": 6,
6972+ "end_line": 6,
6973+ "start_column": 3,
6974+ "end_column": 60,
6975+ "state": "open",
6976+ "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
6977+ "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6978+ "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
6979+ "created_at": "2026-10-06T09:14:02.118Z",
6980+ "updated_at": "2026-10-06T09:14:02.118Z",
6981+ "fixed_at": null,
6982+ "dismissed_by": null,
6983+ "dismissed_reason": null,
6984+ "dismissed_comment": null,
6985+ "dismissed_at": null,
6986+ "issue": null
6987+ }
6988+ }
6989+ ]
6990+ },
6991+ "get_code_scanning_alert": {
6992+ "params": {
6993+ "owner": "flagon-io",
6994+ "name": "hello",
6995+ "number": 4
6996+ },
6997+ "response": {
6998+ "alert": {
6999+ "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
7000+ "number": 4,
7001+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7002+ "tool": "Semgrep OSS",
7003+ "category": "Semgrep OSS",
7004+ "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
7005+ "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
7006+ "rule_description": "Detected calls to child_process from a function argument.",
7007+ "help": null,
7008+ "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
7009+ "tags": [
7010+ "security",
7011+ "CWE-78"
7012+ ],
7013+ "level": "error",
7014+ "security_severity": null,
7015+ "severity": "high",
7016+ "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
7017+ "path": "src/server.js",
7018+ "start_line": 6,
7019+ "end_line": 6,
7020+ "start_column": 3,
7021+ "end_column": 60,
7022+ "state": "open",
7023+ "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
7024+ "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7025+ "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7026+ "created_at": "2026-10-06T09:14:02.118Z",
7027+ "updated_at": "2026-10-06T09:14:02.118Z",
7028+ "fixed_at": null,
7029+ "dismissed_by": null,
7030+ "dismissed_reason": null,
7031+ "dismissed_comment": null,
7032+ "dismissed_at": null,
7033+ "issue": null
7034+ },
7035+ "activity": [],
7036+ "analyses": [
7037+ {
7038+ "id": "ana_01kq2rbh8j9k0m1n2p3q4r5s6t",
7039+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7040+ "sarif_id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7041+ "tool": "Semgrep OSS",
7042+ "tool_version": "1.140.0",
7043+ "category": "Semgrep OSS",
7044+ "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7045+ "git_ref": "refs/heads/main",
7046+ "pull": null,
7047+ "results": 7,
7048+ "new_alerts": 2,
7049+ "fixed_alerts": 1,
7050+ "dropped": 0,
7051+ "created_at": "2026-10-06T09:14:02.118Z"
7052+ }
7053+ ]
7054+ }
7055+ },
7056+ "update_code_scanning_alert": {
7057+ "params": {
7058+ "owner": "flagon-io",
7059+ "name": "hello",
7060+ "number": 4
7061+ },
7062+ "request": {
7063+ "state": "dismissed",
7064+ "dismissed_reason": "false_positive",
7065+ "dismissed_comment": "The argument is a constant."
7066+ },
7067+ "response": {
7068+ "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s",
7069+ "number": 4,
7070+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7071+ "tool": "Semgrep OSS",
7072+ "category": "Semgrep OSS",
7073+ "rule_id": "javascript.lang.security.detect-child-process.detect-child-process",
7074+ "rule_name": "javascript.lang.security.detect-child-process.detect-child-process",
7075+ "rule_description": "Detected calls to child_process from a function argument.",
7076+ "help": null,
7077+ "help_uri": "https://semgrep.dev/r/javascript.lang.security.detect-child-process.detect-child-process",
7078+ "tags": [
7079+ "security",
7080+ "CWE-78"
7081+ ],
7082+ "level": "error",
7083+ "security_severity": null,
7084+ "severity": "high",
7085+ "message": "Detected calls to child_process from a function argument `req`. This could lead to a command injection.",
7086+ "path": "src/server.js",
7087+ "start_line": 6,
7088+ "end_line": 6,
7089+ "start_column": 3,
7090+ "end_column": 60,
7091+ "state": "dismissed",
7092+ "fingerprint": "3f1c9a0e7b2d4c5e6f708192a3b4c5d6",
7093+ "first_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7094+ "last_commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7095+ "created_at": "2026-10-06T09:14:02.118Z",
7096+ "updated_at": "2026-10-06T09:14:02.118Z",
7097+ "fixed_at": null,
7098+ "dismissed_by": "syntaqx",
7099+ "dismissed_reason": "false_positive",
7100+ "dismissed_comment": "The argument is a constant.",
7101+ "dismissed_at": "2026-10-06T09:20:41.502Z",
7102+ "issue": null
7103+ }
7104+ },
7105+ "list_code_scanning_analyses": {
7106+ "params": {
7107+ "owner": "flagon-io",
7108+ "name": "hello"
7109+ },
7110+ "response": [
7111+ {
7112+ "id": "ana_01kq2rbh8j9k0m1n2p3q4r5s6t",
7113+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7114+ "sarif_id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7115+ "tool": "Semgrep OSS",
7116+ "tool_version": "1.140.0",
7117+ "category": "Semgrep OSS",
7118+ "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7119+ "git_ref": "refs/heads/main",
7120+ "pull": null,
7121+ "results": 7,
7122+ "new_alerts": 2,
7123+ "fixed_alerts": 1,
7124+ "dropped": 0,
7125+ "created_at": "2026-10-06T09:14:02.118Z"
7126+ }
7127+ ]
7128+ },
7129+ "upload_sarif": {
7130+ "params": {
7131+ "owner": "flagon-io",
7132+ "name": "hello"
7133+ },
7134+ "request": {
7135+ "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7136+ "ref": "refs/heads/main",
7137+ "sarif": "H4sIAAAAAAAA…",
7138+ "checkout_uri": "file:///home/runner/work/repo"
7139+ },
7140+ "response": {
7141+ "id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7142+ "processing_status": "complete",
7143+ "analyses": [
7144+ "ana_01kq2rbh8j9k0m1n2p3q4r5s6t"
7145+ ],
7146+ "errors": [],
7147+ "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7148+ "git_ref": "refs/heads/main",
7149+ "created_at": "2026-10-06T09:14:02.118Z"
7150+ },
7151+ "notes": "`sarif` is the SARIF 2.1.0 file gzipped, then base64-encoded: `gzip -c results.sarif | base64 -w0`. The upload is read at once: `processing_status` is `complete` or `failed`, with `errors` saying why. For `refs/pull/<number>/head`, the results become the pull request's `Code scanning` check instead of alerts."
7152+ },
7153+ "get_sarif_upload": {
7154+ "params": {
7155+ "owner": "flagon-io",
7156+ "name": "hello",
7157+ "id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v"
7158+ },
7159+ "response": {
7160+ "id": "sar_01kq2scj9k0m1n2p3q4r5s6t7v",
7161+ "processing_status": "complete",
7162+ "analyses": [
7163+ "ana_01kq2rbh8j9k0m1n2p3q4r5s6t"
7164+ ],
7165+ "errors": [],
7166+ "commit_sha": "4807077b296e6edbf410d55e72749d3e1170c291",
7167+ "git_ref": "refs/heads/main",
7168+ "created_at": "2026-10-06T09:14:02.118Z"
7169+ }
7170+ },
7171+ "list_vulnerability_alerts": {
7172+ "params": {
7173+ "owner": "flagon-io",
7174+ "name": "hello"
7175+ },
7176+ "query": {
7177+ "state": "open"
7178+ },
7179+ "response": [
7180+ {
7181+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7182+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7183+ "ecosystem": "npm",
7184+ "package": "lodash",
7185+ "version": "4.17.20",
7186+ "manifest": "package-lock.json",
7187+ "advisory": "GHSA-35jh-r3h4-6jhm",
7188+ "osv_id": "GHSA-35jh-r3h4-6jhm",
7189+ "summary": "Command Injection in lodash",
7190+ "severity": "high",
7191+ "fixed_version": "4.17.21",
7192+ "status": "open",
7193+ "issue": null,
7194+ "found_at": "2026-10-06T09:14:02.118Z",
7195+ "fixed_at": null,
7196+ "state": "open",
7197+ "dismissed_by": null,
7198+ "dismissed_reason": null,
7199+ "dismissed_comment": null,
7200+ "dismissed_at": null,
7201+ "update": null
7202+ }
7203+ ]
7204+ },
7205+ "list_vulnerability_alerts_for_workspace": {
7206+ "params": {
7207+ "workspace": "flagon-io"
7208+ },
7209+ "query": {
7210+ "severity": "critical"
7211+ },
7212+ "response": [
7213+ {
7214+ "repo": "hello",
7215+ "vulnerability": {
7216+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7217+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7218+ "ecosystem": "npm",
7219+ "package": "lodash",
7220+ "version": "4.17.20",
7221+ "manifest": "package-lock.json",
7222+ "advisory": "GHSA-35jh-r3h4-6jhm",
7223+ "osv_id": "GHSA-35jh-r3h4-6jhm",
7224+ "summary": "Command Injection in lodash",
7225+ "severity": "high",
7226+ "fixed_version": "4.17.21",
7227+ "status": "open",
7228+ "issue": null,
7229+ "found_at": "2026-10-06T09:14:02.118Z",
7230+ "fixed_at": null,
7231+ "state": "open",
7232+ "dismissed_by": null,
7233+ "dismissed_reason": null,
7234+ "dismissed_comment": null,
7235+ "dismissed_at": null,
7236+ "update": null
7237+ }
7238+ }
7239+ ]
7240+ },
7241+ "get_vulnerability_alert": {
7242+ "params": {
7243+ "owner": "flagon-io",
7244+ "name": "hello",
7245+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n"
7246+ },
7247+ "response": {
7248+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7249+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7250+ "ecosystem": "npm",
7251+ "package": "lodash",
7252+ "version": "4.17.20",
7253+ "manifest": "package-lock.json",
7254+ "advisory": "GHSA-35jh-r3h4-6jhm",
7255+ "osv_id": "GHSA-35jh-r3h4-6jhm",
7256+ "summary": "Command Injection in lodash",
7257+ "severity": "high",
7258+ "fixed_version": "4.17.21",
7259+ "status": "open",
7260+ "issue": null,
7261+ "found_at": "2026-10-06T09:14:02.118Z",
7262+ "fixed_at": null,
7263+ "state": "open",
7264+ "dismissed_by": null,
7265+ "dismissed_reason": null,
7266+ "dismissed_comment": null,
7267+ "dismissed_at": null,
7268+ "update": null
7269+ }
7270+ },
7271+ "update_vulnerability_alert": {
7272+ "params": {
7273+ "owner": "flagon-io",
7274+ "name": "hello",
7275+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n"
7276+ },
7277+ "request": {
7278+ "state": "dismissed",
7279+ "reason": "tolerable_risk",
7280+ "comment": "Only the build uses it."
7281+ },
7282+ "response": {
7283+ "id": "vul_01kp4b8c3d4e5f6g7h8j9k0m1n",
7284+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7285+ "ecosystem": "npm",
7286+ "package": "lodash",
7287+ "version": "4.17.20",
7288+ "manifest": "package-lock.json",
7289+ "advisory": "GHSA-35jh-r3h4-6jhm",
7290+ "osv_id": "GHSA-35jh-r3h4-6jhm",
7291+ "summary": "Command Injection in lodash",
7292+ "severity": "high",
7293+ "fixed_version": "4.17.21",
7294+ "status": "dismissed",
7295+ "issue": null,
7296+ "found_at": "2026-10-06T09:14:02.118Z",
7297+ "fixed_at": null,
7298+ "state": "dismissed",
7299+ "dismissed_by": "syntaqx",
7300+ "dismissed_reason": "tolerable_risk",
7301+ "dismissed_comment": "Only the build uses it.",
7302+ "dismissed_at": "2026-10-06T09:20:41.502Z",
7303+ "update": null
7304+ }
7305+ },
7306+ "fix_security_alert": {
7307+ "params": {
7308+ "owner": "flagon-io",
7309+ "name": "hello",
7310+ "id": "cod_01kq2qag7h8j9k0m1n2p3q4r5s"
7311+ },
7312+ "response": {
7313+ "issue": 57,
7314+ "started": true,
7315+ "message": null
7316+ },
7317+ "notes": "Opens an issue with what is wrong and what done means, and puts g1t on it as you. Its run is charged as agent usage, and its pull request lands through the repository's required checks. Asking again while the issue is open returns it."
7318+ },
7319+ "get_dependency_graph": {
7320+ "params": {
7321+ "owner": "flagon-io",
7322+ "name": "hello"
7323+ },
7324+ "response": {
7325+ "commit": "4807077b296e6edbf410d55e72749d3e1170c291",
7326+ "manifests": [
7327+ {
7328+ "path": "package-lock.json",
7329+ "ecosystem": "npm",
7330+ "dependencies": 2,
7331+ "direct": 1
7332+ }
7333+ ],
7334+ "dependencies": [
7335+ {
7336+ "ecosystem": "npm",
7337+ "name": "lodash",
7338+ "version": "4.17.20",
7339+ "manifest": "package-lock.json",
7340+ "relationship": "direct",
7341+ "development": false,
7342+ "license": "MIT",
7343+ "purl": "pkg:npm/lodash@4.17.20",
7344+ "vulnerabilities": 1
7345+ },
7346+ {
7347+ "ecosystem": "npm",
7348+ "name": "ms",
7349+ "version": "2.1.3",
7350+ "manifest": "package-lock.json",
7351+ "relationship": "transitive",
7352+ "development": false,
7353+ "license": "MIT",
7354+ "purl": "pkg:npm/ms@2.1.3",
7355+ "vulnerabilities": 0
7356+ }
7357+ ]
7358+ }
7359+ },
7360+ "get_sbom": {
7361+ "params": {
7362+ "owner": "flagon-io",
7363+ "name": "hello"
7364+ },
7365+ "response": {
7366+ "sbom": {
7367+ "spdxVersion": "SPDX-2.3",
7368+ "dataLicense": "CC0-1.0",
7369+ "SPDXID": "SPDXRef-DOCUMENT",
7370+ "name": "flagon-io/hello dependency graph",
7371+ "documentNamespace": "https://g1t.sh/flagon-io/hello/sbom/sbom_01kq2tdk0m1n2p3q4r5s6t7v8w",
7372+ "creationInfo": {
7373+ "created": "2026-10-06T09:14:02Z",
7374+ "creators": [
7375+ "Tool: g1t",
7376+ "Organization: g1t"
7377+ ],
7378+ "comment": "Read from the repository's lockfiles on its default branch."
7379+ },
7380+ "documentDescribes": [
7381+ "SPDXRef-Repository-flagon-io-hello"
7382+ ],
7383+ "packages": [
7384+ {
7385+ "SPDXID": "SPDXRef-Repository-flagon-io-hello",
7386+ "name": "flagon-io/hello",
7387+ "versionInfo": "4807077b296e6edbf410d55e72749d3e1170c291",
7388+ "downloadLocation": "git+https://g1t.sh/flagon-io/hello.git",
7389+ "filesAnalyzed": false,
7390+ "licenseConcluded": "NOASSERTION",
7391+ "licenseDeclared": "NOASSERTION",
7392+ "copyrightText": "NOASSERTION",
7393+ "primaryPackagePurpose": "SOURCE",
7394+ "externalRefs": []
7395+ },
7396+ {
7397+ "SPDXID": "SPDXRef-Package-npm-lodash-4.17.20",
7398+ "name": "lodash",
7399+ "versionInfo": "4.17.20",
7400+ "downloadLocation": "NOASSERTION",
7401+ "filesAnalyzed": false,
7402+ "licenseConcluded": "NOASSERTION",
7403+ "licenseDeclared": "MIT",
7404+ "copyrightText": "NOASSERTION",
7405+ "primaryPackagePurpose": "LIBRARY",
7406+ "comment": "Resolved by package-lock.json (direct dependency).",
7407+ "externalRefs": [
7408+ {
7409+ "referenceCategory": "PACKAGE-MANAGER",
7410+ "referenceType": "purl",
7411+ "referenceLocator": "pkg:npm/lodash@4.17.20"
7412+ }
7413+ ]
7414+ }
7415+ ],
7416+ "relationships": [
7417+ {
7418+ "spdxElementId": "SPDXRef-DOCUMENT",
7419+ "relationshipType": "DESCRIBES",
7420+ "relatedSpdxElement": "SPDXRef-Repository-flagon-io-hello"
7421+ },
7422+ {
7423+ "spdxElementId": "SPDXRef-Repository-flagon-io-hello",
7424+ "relationshipType": "DEPENDS_ON",
7425+ "relatedSpdxElement": "SPDXRef-Package-npm-lodash-4.17.20"
7426+ }
7427+ ]
7428+ }
7429+ },
7430+ "notes": "`sbom` is an SPDX 2.3 JSON document, sent as SPDX spells it. Save it with `jq .sbom`."
7431+ },
7432+ "compare_dependencies": {
7433+ "params": {
7434+ "owner": "flagon-io",
7435+ "name": "hello",
7436+ "basehead": "main...upgrade-deps"
7437+ },
7438+ "response": {
7439+ "base": "main",
7440+ "head": "upgrade-deps",
7441+ "changes": [
7442+ {
7443+ "change_type": "added",
7444+ "manifest": "package-lock.json",
7445+ "ecosystem": "npm",
7446+ "name": "lodash",
7447+ "version": "4.17.20",
7448+ "relationship": "direct",
7449+ "development": false,
7450+ "license": "MIT",
7451+ "purl": "pkg:npm/lodash@4.17.20",
7452+ "vulnerabilities": [
7453+ {
7454+ "advisory": "GHSA-35jh-r3h4-6jhm",
7455+ "osv_id": "GHSA-35jh-r3h4-6jhm",
7456+ "summary": "Command Injection in lodash",
7457+ "severity": "high",
7458+ "fixed_version": "4.17.21",
7459+ "url": "https://osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm"
7460+ }
7461+ ],
7462+ "denied_license": false,
7463+ "failing": true
7464+ },
7465+ {
7466+ "change_type": "removed",
7467+ "manifest": "package-lock.json",
7468+ "ecosystem": "npm",
7469+ "name": "lodash",
7470+ "version": "4.17.21",
7471+ "relationship": "direct",
7472+ "development": false,
7473+ "license": "MIT",
7474+ "purl": "pkg:npm/lodash@4.17.21",
7475+ "vulnerabilities": [],
7476+ "denied_license": false,
7477+ "failing": false
7478+ }
7479+ ],
7480+ "passed": false,
7481+ "headline": "Adds 1 vulnerable package",
7482+ "fail_on": "high",
7483+ "deny_licenses": []
7484+ }
7485+ },
7486+ "get_security_settings": {
7487+ "params": {
7488+ "owner": "flagon-io",
7489+ "name": "hello"
7490+ },
7491+ "response": {
7492+ "settings": {
7493+ "code_scanning_gate": "high",
7494+ "dependency_review": true,
7495+ "review_fail_on": "high",
7496+ "review_deny_licenses": [
7497+ "AGPL-3.0-only"
7498+ ],
7499+ "review_comment": true
7500+ },
7501+ "workspace": {
7502+ "delegated_bypass": true,
7503+ "validity_checks": true
7504+ },
7505+ "private": true,
7506+ "entitled": true,
7507+ "upkeep": true
7508+ }
7509+ },
7510+ "update_security_settings": {
7511+ "params": {
7512+ "owner": "flagon-io",
7513+ "name": "hello"
7514+ },
7515+ "request": {
7516+ "code_scanning_gate": "high",
7517+ "review_deny_licenses": [
7518+ "AGPL-3.0-only"
7519+ ]
7520+ },
7521+ "response": {
7522+ "settings": {
7523+ "code_scanning_gate": "high",
7524+ "dependency_review": true,
7525+ "review_fail_on": "high",
7526+ "review_deny_licenses": [
7527+ "AGPL-3.0-only"
7528+ ],
7529+ "review_comment": true
7530+ },
7531+ "workspace": {
7532+ "delegated_bypass": true,
7533+ "validity_checks": true
7534+ },
7535+ "private": true,
7536+ "entitled": true,
7537+ "upkeep": true
7538+ },
7539+ "notes": "Only what you send changes. The `Code scanning` and `Dependency review` checks gate merges once you require them in branch protection."
7540+ },
7541+ "get_workspace_security_settings": {
7542+ "params": {
7543+ "workspace": "flagon-io"
7544+ },
7545+ "response": {
7546+ "settings": {
7547+ "delegated_bypass": true,
7548+ "validity_checks": true
7549+ },
7550+ "activated": true
7551+ }
7552+ },
7553+ "update_workspace_security_settings": {
7554+ "params": {
7555+ "workspace": "flagon-io"
7556+ },
7557+ "request": {
7558+ "delegated_bypass": true
7559+ },
7560+ "response": {
7561+ "settings": {
7562+ "delegated_bypass": true,
7563+ "validity_checks": true
7564+ },
7565+ "activated": true
7566+ }
7567+ },
7568+ "get_security_overview": {
7569+ "params": {
7570+ "workspace": "flagon-io"
7571+ },
7572+ "query": {
7573+ "days": "30"
7574+ },
7575+ "response": {
7576+ "activated": true,
7577+ "private_hidden": 0,
7578+ "totals": [
7579+ {
7580+ "alert_type": "secret_scanning",
7581+ "open": {
7582+ "critical": 1,
7583+ "high": 0,
7584+ "medium": 0,
7585+ "low": 0,
7586+ "unknown": 0
7587+ },
7588+ "opened": 2,
7589+ "closed": 1
7590+ },
7591+ {
7592+ "alert_type": "code_scanning",
7593+ "open": {
7594+ "critical": 0,
7595+ "high": 3,
7596+ "medium": 4,
7597+ "low": 0,
7598+ "unknown": 0
7599+ },
7600+ "opened": 7,
7601+ "closed": 2
7602+ },
7603+ {
7604+ "alert_type": "vulnerability",
7605+ "open": {
7606+ "critical": 0,
7607+ "high": 1,
7608+ "medium": 2,
7609+ "low": 1,
7610+ "unknown": 0
7611+ },
7612+ "opened": 3,
7613+ "closed": 5
7614+ }
7615+ ],
7616+ "trend": [
7617+ {
7618+ "day": "2026-10-05",
7619+ "secret_scanning": 1,
7620+ "code_scanning": 8,
7621+ "vulnerability": 6
7622+ },
7623+ {
7624+ "day": "2026-10-06",
7625+ "secret_scanning": 1,
7626+ "code_scanning": 7,
7627+ "vulnerability": 4
7628+ }
7629+ ],
7630+ "repos": [
7631+ {
7632+ "repo_id": "rep_01kp0a1b2c3d4e5f6g7h8j9k0m",
7633+ "name": "hello",
7634+ "private": true,
7635+ "custom_patterns": 1,
7636+ "validity_checks": true,
7637+ "code_scanning_at": "2026-10-06T09:14:02.118Z",
7638+ "dependency_review": true,
7639+ "security_updates": true,
7640+ "lockfiles": 1,
7641+ "secrets": {
7642+ "critical": 1,
7643+ "high": 0,
7644+ "medium": 0,
7645+ "low": 0,
7646+ "unknown": 0
7647+ },
7648+ "code": {
7649+ "critical": 0,
7650+ "high": 3,
7651+ "medium": 4,
7652+ "low": 0,
7653+ "unknown": 0
7654+ },
7655+ "vulnerabilities": {
7656+ "critical": 0,
7657+ "high": 1,
7658+ "medium": 2,
7659+ "low": 1,
7660+ "unknown": 0
7661+ }
7662+ }
7663+ ]
7664+ }
7665+ },
7666+ "create_label": {
7667+ "request": {
7668+ "label": "area: cli",
7669+ "color": "1d76db",
7670+ "description": "The command-line tool"
7671+ },
7672+ "response": {
7673+ "name": "area: cli",
7674+ "color": "1d76db",
7675+ "description": "The command-line tool",
7676+ "issues": 0,
7677+ "pulls": 0
7678+ }
7679+ },
7680+ "update_label": {
7681+ "params": {
7682+ "label": "area: cli"
7683+ },
7684+ "request": {
7685+ "new_name": "cli",
7686+ "color": "0052cc"
7687+ },
7688+ "response": {
7689+ "name": "cli",
7690+ "color": "0052cc",
7691+ "description": "The command-line tool",
7692+ "issues": 3,
7693+ "pulls": 1
7694+ },
7695+ "notes": "Renaming a label renames it on every issue and pull request that carries it."
7696+ },
7697+ "delete_label": {
7698+ "params": {
7699+ "label": "wontfix"
7700+ },
7701+ "response": true
7702+ },
7703+ "add_default_labels": {
7704+ "response": [
7705+ {
7706+ "name": "bug",
7707+ "color": "d73a4a",
7708+ "description": "Something isn't working",
7709+ "issues": 4,
7710+ "pulls": 1
7711+ },
7712+ {
7713+ "name": "documentation",
7714+ "color": "0075ca",
7715+ "description": "Improvements or additions to documentation",
7716+ "issues": 0,
7717+ "pulls": 0
7718+ }
7719+ ],
7720+ "notes": "Every label the repository has afterwards, shortened here. Labels it already had are left as they were."
7721+ },
7722+ "list_issue_labels": {
7723+ "response": [
7724+ {
7725+ "name": "bug",
7726+ "color": "d73a4a",
7727+ "description": "Something isn't working",
7728+ "issues": 4,
7729+ "pulls": 1
7730+ },
7731+ {
7732+ "name": "help wanted",
7733+ "color": "008672",
7734+ "description": "Extra attention is needed",
7735+ "issues": 1,
7736+ "pulls": 0
7737+ }
7738+ ]
7739+ },
7740+ "add_issue_labels": {
7741+ "request": {
7742+ "labels": [
7743+ "help wanted"
7744+ ]
7745+ },
7746+ "response": [
7747+ "bug",
7748+ "help wanted"
7749+ ],
7750+ "notes": "Returns its labels now, by name."
7751+ },
7752+ "set_issue_labels": {
7753+ "request": {
7754+ "labels": [
7755+ "bug"
7756+ ]
7757+ },
7758+ "response": [
7759+ "bug"
7760+ ]
7761+ },
7762+ "remove_issue_labels": {
7763+ "response": []
7764+ },
7765+ "remove_issue_label": {
7766+ "params": {
7767+ "label": "help wanted"
7768+ },
7769+ "response": [
7770+ "bug"
7771+ ]
7772+ },
7773+ "list_milestones": {
7774+ "response": [
7775+ {
7776+ "number": 3,
7777+ "title": "Launch",
7778+ "description": "Everything that has to land before the launch on October 14.",
7779+ "due_on": "2026-10-14",
7780+ "state": "open",
7781+ "open_items": 5,
7782+ "closed_items": 12,
7783+ "created_at": "2026-09-20T09:00:00.000Z",
7784+ "updated_at": "2026-10-06T16:12:40.118Z",
7785+ "closed_at": null
7786+ }
7787+ ],
7788+ "notes": "Open milestones soonest due first, then closed ones. Progress is closed_items out of open_items plus closed_items."
7789+ },
7790+ "create_milestone": {
7791+ "request": {
7792+ "title": "Launch",
7793+ "description": "Everything that has to land before the launch on October 14.",
7794+ "due_on": "2026-10-14"
7795+ },
7796+ "response": {
7797+ "number": 3,
7798+ "title": "Launch",
7799+ "description": "Everything that has to land before the launch on October 14.",
7800+ "due_on": "2026-10-14",
7801+ "state": "open",
7802+ "open_items": 0,
7803+ "closed_items": 0,
7804+ "created_at": "2026-09-20T09:00:00.000Z",
7805+ "updated_at": "2026-09-20T09:00:00.000Z",
7806+ "closed_at": null
7807+ }
7808+ },
7809+ "update_milestone": {
7810+ "params": {
7811+ "milestone": 3
7812+ },
7813+ "request": {
7814+ "state": "closed"
7815+ },
7816+ "response": {
7817+ "number": 3,
7818+ "title": "Launch",
7819+ "description": "Everything that has to land before the launch on October 14.",
7820+ "due_on": "2026-10-14",
7821+ "state": "closed",
7822+ "open_items": 0,
7823+ "closed_items": 17,
7824+ "created_at": "2026-09-20T09:00:00.000Z",
7825+ "updated_at": "2026-10-14T18:00:00.000Z",
7826+ "closed_at": "2026-10-14T18:00:00.000Z"
7827+ }
7828+ },
7829+ "delete_milestone": {
7830+ "params": {
7831+ "milestone": 3
7832+ },
7833+ "response": true
7834+ },
7835+ "get_milestone": {
7836+ "params": {
7837+ "milestone": 3
7838+ },
7839+ "response": {
7840+ "milestone": {
7841+ "number": 3,
7842+ "title": "Launch",
7843+ "description": "Everything that has to land before the launch on October 14.",
7844+ "due_on": "2026-10-14",
7845+ "state": "open",
7846+ "open_items": 5,
7847+ "closed_items": 12,
7848+ "created_at": "2026-09-20T09:00:00.000Z",
7849+ "updated_at": "2026-10-06T16:12:40.118Z",
7850+ "closed_at": null
7851+ },
7852+ "issues": [
7853+ {
7854+ "id": "iss_01m43shrzpfe49x74ga7sj1c6v",
7855+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
7856+ "number": 12,
7857+ "title": "Greeting should name the caller",
7858+ "body": "Take a name from the first argument; fall back to world.",
7859+ "labels": [
7860+ "feature",
7861+ "good first issue"
7862+ ],
7863+ "state": "open",
7864+ "reason": null,
7865+ "resolved_by": null,
7866+ "author": {
7867+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
7868+ "username": "syntaqx",
7869+ "kind": "user",
7870+ "verified": false,
7871+ "workspaces": []
7872+ },
7873+ "requested_by": null,
7874+ "created_at": "2026-10-01T18:04:11.482Z",
7875+ "updated_at": "2026-10-01T18:09:47.305Z",
7876+ "closed_at": null,
7877+ "pull_count": 0,
7878+ "comment_count": 0,
7879+ "assignees": [
7880+ "syntaqx"
7881+ ],
7882+ "blocked_by": [],
7883+ "queued": false,
7884+ "agent": null,
7885+ "milestone": {
7886+ "number": 3,
7887+ "title": "Launch"
7888+ }
7889+ }
7890+ ],
7891+ "pulls": [
7892+ {
7893+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
7894+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
7895+ "number": 14,
7896+ "issue": 12,
7897+ "title": "Greeting should name the caller",
7898+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
7899+ "agent": "claude-code",
7900+ "runtime": "external",
7901+ "status": "open",
7902+ "fork": {
7903+ "namespace": "pulls",
7904+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
7905+ },
7906+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
7907+ "branch": null,
7908+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
7909+ "merge_base": null,
7910+ "merged_by": null,
7911+ "merged_at": null,
7912+ "superseded_by": null,
7913+ "check_status": "passed",
7914+ "files": [
7915+ {
7916+ "path": "src/main.rs",
7917+ "additions": 6,
7918+ "deletions": 2
7919+ }
7920+ ],
7921+ "assignees": [],
7922+ "reviewers": [
7923+ "ana"
7924+ ],
7925+ "labels": [],
7926+ "milestone": {
7927+ "number": 3,
7928+ "title": "Launch"
7929+ },
7930+ "base": "main",
7931+ "author": {
7932+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
7933+ "username": "syntaqx",
7934+ "kind": "user",
7935+ "verified": false,
7936+ "workspaces": []
7937+ },
7938+ "requested_by": null,
7939+ "created_at": "2026-10-01T18:20:02.117Z",
7940+ "updated_at": "2026-10-01T18:35:44.902Z",
7941+ "confidence": null
7942+ }
7943+ ]
7944+ }
7945+ },
7946+ "update_pull_request": {
7947+ "request": {
7948+ "base": "release/1.x",
7949+ "labels": [
7950+ "bug"
7951+ ]
7952+ },
7953+ "response": {
7954+ "id": "pr_01m43smh3vexsr5pmp60qwv0vs",
7955+ "repo_id": "rep_01m3m5q6p0e2qaw6mmjahk0qrr",
7956+ "number": 14,
7957+ "issue": 12,
7958+ "title": "Greeting should name the caller",
7959+ "body": "Reads a name from the first argument. `hello ana` prints \"Hello, ana!\".",
7960+ "agent": "claude-code",
7961+ "runtime": "external",
7962+ "status": "open",
7963+ "fork": {
7964+ "namespace": "pulls",
7965+ "name": "pr_01m43smh3vexsr5pmp60qwv0vs"
7966+ },
7967+ "fork_repo_id": "rep_01m43smh5xd7aw2kq9tv0b4c8e",
7968+ "branch": null,
7969+ "head_commit": "9f2c4e1a7b3d5f60812a4c6e8b0d2f4a6c8e0b13",
7970+ "merge_base": null,
7971+ "merged_by": null,
7972+ "merged_at": null,
7973+ "superseded_by": null,
7974+ "check_status": "passed",
7975+ "files": [
7976+ {
7977+ "path": "src/main.rs",
7978+ "additions": 6,
7979+ "deletions": 2
7980+ }
7981+ ],
7982+ "assignees": [],
7983+ "reviewers": [
7984+ "ana"
7985+ ],
7986+ "labels": [
7987+ "bug"
7988+ ],
7989+ "milestone": null,
7990+ "base": "release/1.x",
7991+ "author": {
7992+ "id": "usr_01kkntcg1eeb98j62xjm7eh09p",
7993+ "username": "syntaqx",
7994+ "kind": "user",
7995+ "verified": false,
7996+ "workspaces": []
7997+ },
7998+ "requested_by": null,
7999+ "created_at": "2026-10-01T18:20:02.117Z",
8000+ "updated_at": "2026-10-01T18:35:44.902Z",
8001+ "confidence": null
8002+ },
8003+ "notes": "A new base takes it out of the merge queue, and whether it is behind, merges cleanly and has the checks it needs is worked out against the new base."
8004+ }
79788005 }
+7−0
163163 granted invites, or else one of yours (see
164164 [invites](/guides/authentication/#invites)), and works for 30 days.
165165
166+On a free workspace, only the first row works: its members can be given a
167+role, but nobody else can be invited until the workspace starts the g1t
168+plan. **Add people** says **Start the plan to invite people** above the
169+form, and an invitation is refused with `402` (`payment_required`). An
170+invitation sent before cannot be accepted until then. See
171+[who a free workspace can add](/guides/usage-and-billing/#who-a-free-workspace-can-add).
172+
166173 To change someone's role, pick another beside their name. To take it away,
167174 choose **Remove**. Removing takes away only the role given on this
168175 repository: an owner's Admin, a member's base permission and what their
+119−9
3737 deployments and semantic search need [the g1t plan](#the-g1t-plan), or a
3838 [card check](#no-card-no-compute) for the trial and the open-source pool.
3939
40+### One free workspace per person
41+
42+Each person can own **one free workspace**: a workspace that is not on the
43+g1t plan, an enterprise's terms or a full discount. A new workspace starts
44+free, so while you own a free workspace, creating another is refused with
45+the way forward:
46+
47+1. Start the plan on the free workspace you have
48+ ([Start or end the plan](#start-or-end-the-plan)), or
49+2. delete it, if you no longer use it
50+ ([Delete a workspace](/guides/workspaces/)).
51+
52+Then create the new one. If you owned several free workspaces before this
53+rule, you keep them all, but you cannot create another until each of them
54+is on the plan or deleted. Workspaces you belong to without owning them do
55+not count. The site's **New workspace** page says so before you start;
56+`POST /workspaces` and the MCP `workspace` tool's `create` action answer
57+`402` (`payment_required`) with the same message.
58+
59+### Who a free workspace can add
60+
61+A free workspace keeps the people already in it, but **cannot add anyone**
62+until it starts the plan:
63+
64+- no new members, by username or by email invite;
65+- no outside collaborators on its repositories, and no invitations to them;
66+- an invite or invitation sent before cannot be accepted until then (it
67+ waits, and works once the plan is on).
68+
69+Its members can still be given a role on its repositories, and put on its
70+[teams](/guides/teams/). On the **People** page and a repository's
71+**Settings → Access**, an owner sees **Start the plan to invite people**
72+with a button to the plan. Through the API and MCP, adding a member,
73+inviting, adding an outside collaborator and accepting are refused with
74+`402` (`payment_required`). g1t's own agent, `@g1t`, works in every
75+workspace and never counts as someone added.
76+
4077 Your own machines are. Workflow jobs on
4178 [self-hosted runners](/guides/self-hosted-runners/) cost nothing, on every
4279 plan, the free one included, and need no card; their minutes show on usage
4683 ## The g1t plan
4784
4885 One plan, **$20 a month per workspace**, however many people and agents
49−are in it. It is never priced per person.
86+are in it. It is never priced per person. Like every price on g1t, it
87+excludes tax ([Tax](#tax)), and paid by card it carries Stripe's
88+[card processing fee](#card-processing-fee) as its own line, $0.91 a month
89+on $20.
5090
5191 - **$10 of usage each month** at cost plus 20%, used first.
5292 - **Everyone in the workspace** at one price, never per person.
537577 asks. A bank transfer page gives the account details, and the amount
538578 counts when the money arrives.
539579
580+By card, the [card processing fee](#card-processing-fee) is its own line
581+(the card shows it for $100, $500 and $1,000); a bank transfer has none.
582+[Tax](#tax) is added where it applies. What you prepay is credited in full:
583+neither the fee nor the tax comes from it.
584+
540585 **Prepaid balance** shows what is paid in advance and not used yet.
541586
542587 ### Caps
608653 amount from $10 to $1,000.
609654 3. Choose **Buy AI credit**, and pay on Stripe's page.
610655
611−Stripe's card fee (2.9% + $0.30) is its own line on that page, **Card
612−processing fee**, so the credit you get is the amount you chose. Invoiced
613−billing never carries it. The credit is added once Stripe says the payment
614−was made, whether or not you come back to g1t, and **expires 1 year after
615−purchase**. The card is kept for auto-reload.
656+The [card processing fee](#card-processing-fee) is its own line on that
657+page, and shown on Billing before you go there (on $25, *Card processing
658+fee $1.06, plus tax where it applies*), so the credit you get is the amount
659+you chose. [Tax](#tax) is added on top where it applies. The credit is
660+added once Stripe says the payment was made, whether or not you come back
661+to g1t, and **expires 1 year after purchase**. The card is kept for
662+auto-reload, which charges the credit, its card fee and its tax together.
616663
617664 ### Auto-reload
618665
681728 charged at once with no minimum. See
682729 [deleting a workspace](/guides/workspaces/#what-billing-needs).
683730
684−Each is charged to the card on file. The Billing page lists them, with
685−links to view each on Stripe and download its PDF.
731+Each is charged to the card on file, with the
732+[card processing fee](#card-processing-fee) and [tax](#tax) as lines of
733+their own. The Billing page lists them, with links to view each on Stripe
734+and download its PDF; each one's amount is the usage, with the fee and
735+tax under it.
736+
737+## Tax
738+
739+Every price on g1t excludes tax. Stripe adds sales tax, VAT or GST where it
740+applies (Stripe Tax), worked out from the workspace's billing address, and
741+shows it as its own line before you pay and on every receipt and invoice.
742+The plan, add-ons, prepaying, AI credit, auto-reload and invoices are all
743+taxed the same way, as software as a service for business use.
744+
745+- **The address.** Stripe's payment pages always ask for a billing
746+ address, and save it as the workspace's **Invoice details**. A card check
747+ saves the card's billing address there too, if there is none yet. You
748+ can change it under [Your card and billing
749+ details](#your-card-and-billing-details).
750+- **A business tax ID.** Add it on Stripe's page or under **Invoice
751+ details** (the kind, such as EU VAT, and the number). Stripe checks it
752+ (**Verified by Stripe**, or **Stripe is checking it**) and applies it
753+ where the law says so, such as a reverse charge.
754+- **No address, no charge.** Where Stripe has nothing to work tax out
755+ from, g1t does not charge the card. Billing shows **Add a billing
756+ address**, the owners are emailed once, and the charge goes through once
757+ the address is saved. Nothing is lost, and work is not stopped for it.
758+ In the United States the ZIP code is needed; elsewhere the country.
759+- **Tax exempt.** If your organisation is exempt, write to
760+ support@g1t.sh with the certificate; Billing then says **Tax exempt**.
761+- **Refunds** give the tax back in proportion.
762+
763+Tax is never part of your balance or usage: the statement shows it as its
764+own line, beside the payment it came with.
765+
766+## Card processing fee
767+
768+Paying by card adds Stripe's fee, **2.9% + $0.30**, as its own line,
769+**Card processing fee**, worked out so that what is left after Stripe's
770+fee is exactly what you paid for: $0.91 on the $20 plan, $1.06 on $25 of
771+AI credit. It is shown before you pay, on every card payment:
772+
773+| Payment | Card fee |
774+| --- | --- |
775+| The plan and add-ons, each month | Yes, a monthly line |
776+| Prepaying by card, and AI credit | Yes |
777+| Auto-reload, and invoices charged to the card | Yes |
778+| Prepaying by bank transfer | No |
779+| An enterprise's invoices | No |
780+
781+Tax applies to the fee as to what it is paid with. The fee pays Stripe, not
782+g1t: usage is still charged at cost plus 20%, and models at the provider's
783+price plus the agent rate. The statement shows card fees as their own line,
784+never from your balance.
686785
687786 ### The minimum charge
688787
714813 printed on every invoice: the invoice email, company name, billing
715814 address, tax ID (its kind and number), a purchase order, and the invoice
716815 language. An owner edits them here and chooses **Save invoice details**.
816+ [Tax](#tax) is worked out from the address, so the card says when there
817+ is none yet (in the US it needs the ZIP code), shows Stripe's check of
818+ the tax ID, and says **Tax exempt** or **Reverse charge** when that
819+ applies.
717820 - **Invoices** lists every invoice Stripe sent (the plan, add-ons, AI
718821 credit and month-end usage), each with **View** and **PDF**.
719822 - **Add-ons** lists what can be turned on beside the plan, such as the
769872 enterprise is **invoiced**: when each month closes, one invoice goes to
770873 the enterprise's billing address, with a line for each workspace, due in
771874 30 days and paid by card or bank transfer. If it goes overdue, the
772− workspaces' work stops until it is paid.
875+ workspaces' work stops until it is paid. [Tax](#tax) is added from the
876+ enterprise's billing address, which g1t keeps on its Stripe customer, and
877+ an invoice never carries the card processing fee.
773878 - **A discount**: a percentage off every usage charge, from a few percent
774879 to 100%, with a reason, sometimes until a date. Prices themselves stay
775880 the public ones. The statement shows every line at its price and the
870975 | Payments | Card payments and invoices paid. |
871976 | Credits from g1t | Credit g1t added (promotional, goodwill or a refund), and what of it expired or was withdrawn. See [Credits from g1t](#credits-from-g1t). |
872977 | Refunds | Money given back to your card. |
978+ | Tax | Tax paid with that day's payments. Not a charge, and not from your balance. |
979+ | Card processing fees | Card fees paid with that day's payments. Not a charge, and not from your balance. |
980+
981+ Payments are what reached your balance; the tax and card fee paid with
982+ them are the two lines below them, and the totals say what they came to.
873983
874984 - **Covered.** Below the totals, what paid for usage before it was
875985 charged, each with its amount:
+15−0
3232 You can belong to up to ten workspaces. `GET /user`, or the `account` tool's `whoami` action, lists the
3333 ones you belong to.
3434
35+A new workspace is free, and **each person can own one free workspace**.
36+While you own a free workspace, the page shows **You already own a free
37+workspace** in place of the form, with **Start the plan** on it; the API
38+answers `402` (`payment_required`). Start the plan on it, or delete it,
39+then create the new one. Several free workspaces from before are kept, but
40+each needs the plan (or deleting) before you can create another. See
41+[one free workspace per person](/guides/usage-and-billing/#one-free-workspace-per-person).
42+
3543 Usernames and workspaces share one set of names, so a name means the same
3644 thing wherever it appears. Your username is reserved for you: only you can
3745 create a workspace with that name, and nobody can register a username that
294302 To give someone a role on one repository without making them a member,
295303 add them as an [outside collaborator](/guides/access-and-roles/#outside-collaborators).
296304
305+**A free workspace cannot add people.** Until it starts the g1t plan, it
306+cannot add members, send invites, or invite outside collaborators, and an
307+invite sent before waits until the plan is on. Its members stay. People
308+shows **Start the plan to invite people** with the button in place of the
309+form, and the API and MCP answer `402` (`payment_required`). See
310+[who a free workspace can add](/guides/usage-and-billing/#who-a-free-workspace-can-add).
311+
297312 ## The workspace's page
298313
299314 A workspace's own page, `g1t.sh/<workspace>`, has its icon, name, address
+3−3
489489 | --- | --- | --- | --- |
490490 | [`list_collaborators`](/reference/api/access/list-collaborators/) | Everyone with a role on it, with the role, where it comes from (`owner`, `base` or `direct`) and whether they are members; the base permission; and, with the Admin role, pending invitations. Needs the Write role. | `repo` | `access:read` |
491491 | [`get_permission`](/reference/api/access/get-collaborator-permission/) | Someone's role, where it comes from, and what it lets them do. Needs the Write role, or to be about yourself. | `repo`, `username` | `access:read` |
492−| [`add_collaborator`](/reference/api/access/add-collaborator/) | Give someone a role by username or email address. A member gets it at once; anyone else is invited, and becomes an outside collaborator on accepting. Needs the Admin role. | `repo`, `invitee`, `role` | `access:admin` |
492+| [`add_collaborator`](/reference/api/access/add-collaborator/) | Give someone a role by username or email address. A member gets it at once; anyone else is invited, and becomes an outside collaborator on accepting. Needs the Admin role. On a free workspace, only members: inviting anyone else is refused with `402` until it starts the plan. | `repo`, `invitee`, `role` | `access:admin` |
493493 | [`update_collaborator`](/reference/api/access/update-collaborator/) | Change someone's direct role, or their pending invitation's. Needs the Admin role. | `repo`, `username`, `role` | `access:admin` |
494494 | [`remove_collaborator`](/reference/api/access/remove-collaborator/) | Take away someone's direct role. Needs the Admin role, or to be your own. | `repo`, `username` | `access:admin` |
495495 | [`list_invitations`](/reference/api/access/list-repo-invitations/) | Its pending invitations. Needs the Admin role. | `repo` | `access:read` |
533533 | Action | What it does | Required | Scope |
534534 | --- | --- | --- | --- |
535535 | [`get`](/reference/api/workspaces/get-workspace/) | One workspace you belong to: its name, description and member count, its `base_permission` and `team_creation`. Members only. | `workspace` | `workspace:read` |
536−| [`create`](/reference/api/workspaces/create-workspace/) | Create a workspace. | `slug` | `workspace:admin` |
536+| [`create`](/reference/api/workspaces/create-workspace/) | Create a workspace. A new one is free, and each person owns at most one free workspace: refused with `402` while you own one, until it is on the plan or deleted. See [one free workspace per person](/guides/usage-and-billing/#one-free-workspace-per-person). | `slug` | `workspace:admin` |
537537 | [`update`](/reference/api/workspaces/update-workspace/) | Change its display name and description, who may create its teams (`team_creation`: `members` or `owners`), and with the `access:admin` scope too, its `base_permission`. Only the fields given change; the slug never does. Owners only. | `workspace` | `workspace:admin` |
538538 | [`delete`](/reference/api/workspaces/delete-workspace/) | Delete an empty workspace whose billing is settled; `confirm` is its slug. Owners only. See [deleting a workspace](/guides/workspaces/#delete-a-workspace). | `workspace`, `confirm` | `workspace:admin` |
539539 | [`list_invites`](/reference/api/invites/list-workspace-invites/) | A workspace's invites. Owners only. | `workspace` | `workspace:read` |
540−| [`invite_member`](/reference/api/invites/invite-member/) | Invite an address into a workspace, with an invite bound to it. Owners only. | `workspace`, `email` | `workspace:admin` |
540+| [`invite_member`](/reference/api/invites/invite-member/) | Invite an address into a workspace, with an invite bound to it. Owners only. A free workspace cannot invite: refused with `402` until it starts the plan. | `workspace`, `email` | `workspace:admin` |
541541 | [`revoke_invite`](/reference/api/invites/revoke-workspace-invite/) | Revoke a workspace's pending invite. Owners only. | `workspace`, `id` | `workspace:admin` |
542542 | [`list_integrations`](/reference/api/integrations/list-integrations/) | The workspace's connections. Secrets are never returned. Members only. | `workspace` | `workspace:read` |
543543 | [`connect_integration`](/reference/api/integrations/connect-integration/) | Connect a model provider (Anthropic, OpenAI, Gemini, or a compatible endpoint), Sentry, Datadog, a webhook, Jira or Linear, with `config` and `secret`. Owners only. | `workspace`, `provider` | `workspace:admin` |
+0−0

Binary or large file; its contents are not shown.

+24−0
201201 return back("billing-email");
202202 }
203203
204+ if (intent === "billing-address") {
205+ // Where Stripe Tax places the enterprise: an invoice is not sent without it.
206+ const values = fields(form, "line1", "line2", "city", "state", "postalCode", "country", "taxIdType", "taxId");
207+ if (subject.kind !== "enterprise") return failed("top", "Only an enterprise's address is set here; a workspace's owners set their own.");
208+ if (!subject.billingEmail) return failed("address", "Set where its invoices go first: that makes its Stripe customer.", values);
209+ const country = values.country.trim().toUpperCase();
210+ if (!/^[A-Z]{2}$/.test(country)) return failed("address", "The country is two letters, such as US or DE.", values);
211+ if (country === "US" && !values.postalCode.trim()) return failed("address", "In the US, Stripe Tax needs the ZIP code.", values);
212+ const taxIdType = values.taxIdType.trim();
213+ const taxId = values.taxId.trim();
214+ if (Boolean(taxIdType) !== Boolean(taxId)) return failed("address", "Give the tax ID's kind and its number together, or neither.", values);
215+ const address = {
216+ line1: values.line1.trim(),
217+ line2: values.line2.trim(),
218+ city: values.city.trim(),
219+ state: values.state.trim(),
220+ postalCode: values.postalCode.trim(),
221+ country,
222+ };
223+ const result = await admin.enterpriseAddress(subject.accountId, address, taxIdType || null, taxId || null, staff.email);
224+ if (!result.ok) return failed("address", result.error.message, values);
225+ return back("billing-address");
226+ }
227+
204228 if (intent === "invoice") {
205229 if (subject.kind !== "enterprise") return failed("top", "Only an enterprise is invoiced from sudo.");
206230 if (!confirmed) {
+1−0
3333 "reset-stale": "Billing reset. The workspace starts again as a new customer; the costs analysis did not finish, so press Run the analysis now on Costs & margin.",
3434 created: "Enterprise created.",
3535 "billing-email": "Saved where the enterprise's invoices go.",
36+ "billing-address": "Billing address saved on its Stripe customer. Its invoices are taxed from it.",
3637 sales: "Sales record saved.",
3738 note: "Note added.",
3839 payment: "Payment recorded. It is on the workspace's statement and counts toward its limit.",
+2−2
257257 <Field label="And at least, $">
258258 <Input name="anomalyFloor" inputMode="decimal" defaultValue={dollarsField(report.settings.anomalyFloorMicros)} />
259259 </Field>
260− <Field label="Card fee on AI credit bought by card">
260+ <Field label="Card fee on card payments">
261261 <label className="flex h-[38px] items-center gap-2 text-sm text-fg-soft">
262− <input type="checkbox" name="cardFee" defaultChecked={report.settings.cardFee ?? true} className="accent-[var(--g1t-accent)]" /> Passed on as its own line
262+ <input type="checkbox" name="cardFee" defaultChecked={report.settings.cardFee ?? true} className="accent-[var(--g1t-accent)]" /> Its own line; never on invoiced billing or bank transfers
263263 </label>
264264 </Field>
265265 <div className="sm:col-span-2 lg:col-span-4">
+12−0
353353 Every credit
354354 </Link>
355355 </p>
356+ <dl className="mt-3 grid grid-cols-2 gap-3 rounded-lg border border-line bg-surface px-4 py-3 text-sm sm:px-5">
357+ <div>
358+ <dt className="text-xs text-muted">Tax collected</dt>
359+ <dd className="tabular text-fg">{usd(o.taxCollectedMicros ?? 0, { cents: true })}</dd>
360+ <dd className="text-xs text-faint">Owed to tax authorities; never in money in or margin. Filed from Stripe Tax.</dd>
361+ </div>
362+ <div>
363+ <dt className="text-xs text-muted">Card fees passed on</dt>
364+ <dd className="tabular text-fg">{usd(o.cardFeesMicros ?? 0, { cents: true })}</dd>
365+ <dd className="text-xs text-faint">Paid Stripe&apos;s card fees; not revenue either.</dd>
366+ </div>
367+ </dl>
356368 </>
357369 );
358370 }
+43−1
1−import { ArrowLeft, ExternalLink, Mail, Plus, Send, Trash2 } from "lucide-react";
1+import { ArrowLeft, ExternalLink, Mail, MapPin, Plus, Send, Trash2 } from "lucide-react";
22 import { data, Link, redirect, useLocation } from "react-router";
33
44 import { type AdminOwner, type EnterpriseInvoice, type Limit, httpStatus } from "@g1t/contracts";
157157 sent={sent}
158158 pathname={pathname}
159159 error={error("invoices")}
160+ addressError={error("address")}
160161 />
161162 <TermsForm terms={account.terms} pathname={pathname} error={error("terms")} />
162163 <AllowancesForm
306307 sent,
307308 pathname,
308309 error,
310+ addressError,
309311 }: {
310312 email: string | null;
311313 invoices: EnterpriseInvoice[];
312314 sent: EnterpriseInvoice | null;
313315 pathname: string;
314316 error: SectionError;
317+ addressError: SectionError;
315318 }) {
316319 return (
317320 <Section id="invoices" title="Invoices" description="One Stripe invoice for every workspace it pays for, net 30, emailed by Stripe.">
334337 </Button>
335338 </form>
336339
340+ <form method="post" action={`${pathname}#invoices`} className="space-y-2 border-t border-line pt-4">
341+ <input type="hidden" name="intent" value="billing-address" />
342+ <p className="text-sm text-muted">
343+ Billing address, saved on its Stripe customer. Stripe Tax works its invoices&apos; tax out from it, so no invoice goes out without
344+ one. Leave the tax ID blank to keep the one there is.
345+ </p>
346+ {addressError && <Notice tone="error">{addressError.error}</Notice>}
347+ <div className="grid gap-2 sm:grid-cols-2">
348+ <Field label="Street">
349+ <Input name="line1" defaultValue={addressError?.values?.line1 ?? ""} autoComplete="off" />
350+ </Field>
351+ <Field label="Suite, floor">
352+ <Input name="line2" defaultValue={addressError?.values?.line2 ?? ""} autoComplete="off" />
353+ </Field>
354+ <Field label="City">
355+ <Input name="city" defaultValue={addressError?.values?.city ?? ""} autoComplete="off" />
356+ </Field>
357+ <Field label="State or region">
358+ <Input name="state" defaultValue={addressError?.values?.state ?? ""} autoComplete="off" />
359+ </Field>
360+ <Field label="Postal code" hint="Needed in the US">
361+ <Input name="postalCode" defaultValue={addressError?.values?.postalCode ?? ""} autoComplete="off" />
362+ </Field>
363+ <Field label="Country" hint="Two letters, such as US">
364+ <Input name="country" required maxLength={2} defaultValue={addressError?.values?.country ?? ""} className="uppercase" autoComplete="off" />
365+ </Field>
366+ <Field label="Tax ID kind" hint="Stripe's name, such as eu_vat or us_ein">
367+ <Input name="taxIdType" defaultValue={addressError?.values?.taxIdType ?? ""} autoComplete="off" />
368+ </Field>
369+ <Field label="Tax ID">
370+ <Input name="taxId" defaultValue={addressError?.values?.taxId ?? ""} autoComplete="off" />
371+ </Field>
372+ </div>
373+ <Button type="submit" variant="quiet">
374+ <MapPin size={14} />
375+ Save address
376+ </Button>
377+ </form>
378+
337379 <form method="post" action={`${pathname}#review`} className="flex flex-col gap-2 border-t border-line pt-4 sm:flex-row sm:items-center sm:justify-between">
338380 <input type="hidden" name="intent" value="invoice" />
339381 <p className="text-sm text-muted">An invoice goes out on its own when each month closes. Send one now for what it owes so far.</p>
+56−6
77 * an `intent`.
88 */
99 import { ArrowUpRight, Bell, Bot, CreditCard, FileText, Mail, Plus, ReceiptText, Sparkles } from "lucide-react";
10−import type { ReactNode } from "react";
10+import { type ReactNode, useState } from "react";
1111 import { Form, Link } from "react-router";
1212
1313 import type { AiCredit, BillingDetails, FeatureState, Limit, UsageReport } from "@g1t/contracts";
1414
15−import { type PlanStatus, dollars, wholeDollars } from "../lib/billing";
15+import { PLUS_TAX, type PlanStatus, cardFeeCents, dollars, feeAndTax, wholeDollars } from "../lib/billing";
1616 import { money } from "../lib/usage";
1717 import { Card } from "./billing";
1818 import { ErrorText, SubmitButton } from "./ui";
102102 <span className="text-2xl font-semibold tabular-nums tracking-tight">${((plan?.monthlyCents ?? 2000) / 100).toFixed(0)}</span>
103103 <span className="text-sm text-muted"> / month</span>
104104 <span className="block text-xs text-faint">with {wholeDollars(report?.included?.of ?? 10_000_000)} of usage included</span>
105+ {status.kind !== "comped" && status.kind !== "enterprise" && (
106+ <span className="block text-xs text-faint">
107+ {plan?.cardFeeCents ? `+ ${dollars(plan.cardFeeCents * 10_000)} card processing fee, ` : ""}
108+ {plan?.cardFeeCents ? PLUS_TAX : "Plus tax where it applies"}
109+ </span>
110+ )}
105111 </p>
106112 }
107113 >
203209 export function AiCreditCard({ credit, owner, enabled, staff, error }: { credit: AiCredit; owner: boolean; enabled: boolean; staff: boolean; error?: string }) {
204210 const rate = credit.agentRateMicros;
205211 const fee = credit.cardFee;
206− const feeText = fee.on ? `Stripe's card fee (${(fee.percentMicros / 10_000).toFixed(1)}% + ${dollars(fee.fixedCents * 10_000)}) is its own line at checkout.` : "No card fee.";
212+ // What is chosen, so the fee shows before Stripe's page does.
213+ const [chosenCents, setChosenCents] = useState(2_500);
214+ const chosenFee = cardFeeCents(chosenCents, fee);
215+ const stripeFee = `Stripe's ${(fee.percentMicros / 10_000).toFixed(1)}% + ${dollars(fee.fixedCents * 10_000)}`;
216+ const feeText = !fee.on
217+ ? `${feeAndTax(0)}.`
218+ : chosenCents > 0
219+ ? `On $${(chosenCents / 100).toLocaleString("en-US")}: ${feeAndTax(chosenFee).replace(/^C/, "c")} (the fee is ${stripeFee}, its own line at checkout).`
220+ : `A card processing fee (${stripeFee}) is its own line at checkout, ${PLUS_TAX}.`;
221+ const choose = (form: HTMLFormElement) => {
222+ const data = new FormData(form);
223+ const amount = String(data.get("amount") ?? "");
224+ const dollarsChosen = amount === "custom" ? Number(String(data.get("custom") ?? "").replace(/[$,\s]/g, "")) : Number(amount);
225+ setChosenCents(Number.isFinite(dollarsChosen) && dollarsChosen > 0 ? Math.round(dollarsChosen * 100) : 0);
226+ };
207227 return (
208228 <Card
209229 id="ai-credit"
235255 {!credit.freeViaDiscount && !credit.postpaid && (
236256 <>
237257 {credit.canBuy && owner && enabled ? (
238− <Form method="post" className="mt-4">
258+ <Form method="post" className="mt-4" onChange={(event) => choose(event.currentTarget)}>
239259 <input type="hidden" name="intent" value="buy-ai-credit" />
240260 <fieldset className="flex flex-wrap items-center gap-2">
241261 <legend className="mb-2 text-xs text-muted">Buy AI credit</legend>
453473 rows.push({
454474 key: "security",
455475 name: security.plan.title,
456− about: "Custom patterns, validity checks, code scanning and dependency review on private repositories.",
476+ about: `Custom patterns, validity checks, code scanning and dependency review on private repositories. ${
477+ security.plan.cardFeeCents ? `Plus a ${dollars(security.plan.cardFeeCents * 10_000)} card processing fee a month, and tax where it applies.` : "Plus tax where it applies."
478+ }`,
457479 price: `$${(security.plan.monthlyCents / 100).toFixed(security.plan.monthlyCents % 100 ? 2 : 0)} / month`,
458480 on: security.on,
459481 label: security.included ? "Included" : status === "canceling" ? "Ends at the period's end" : security.on ? "On" : "Off",
532554 ["za_vat", "South African VAT"],
533555 ];
534556
557+/** What Stripe's check of a tax ID found. */
558+const TAX_ID_STATUS: Record<string, string> = {
559+ verified: "Verified by Stripe.",
560+ pending: "Stripe is checking it.",
561+ unverified: "Stripe could not verify it. Check the number.",
562+ unavailable: "Stripe cannot check this kind of ID.",
563+};
564+
535565 const LANGUAGES: [string, string][] = [
536566 ["", "Automatic"],
537567 ["en", "English"],
550580 const a = details?.address;
551581 const disabled = !owner || !enabled;
552582 return (
553− <Card id="details" icon={<ReceiptText size={16} />} title="Invoice details" about="Who invoices are for. Kept on the workspace's Stripe customer and printed on every invoice.">
583+ <Card
584+ id="details"
585+ icon={<ReceiptText size={16} />}
586+ title="Invoice details"
587+ about="Who invoices are for. Kept on the workspace's Stripe customer and printed on every invoice. Tax is worked out from the address."
588+ >
589+ {details?.customer && !details.taxLocation && (
590+ <p className={`mt-3 rounded-lg border px-3 py-2 text-sm ${details.taxAddressNeededAt ? "border-warn/40 bg-warn/5" : "border-line bg-bg/40 text-muted"}`}>
591+ {details.taxAddressNeededAt
592+ ? "Add the billing address: Stripe needs at least the country (and in the US the ZIP code) to work out tax, so g1t is not charging the card until it is here."
593+ : "No billing address yet. Stripe needs at least the country (and in the US the ZIP code) to work out tax before g1t charges the card."}
594+ </p>
595+ )}
596+ {(details?.taxExempt === "exempt" || details?.taxExempt === "reverse") && (
597+ <p className="mt-3 text-xs text-muted">
598+ {details.taxExempt === "exempt" ? "Tax exempt: no tax is added." : "Reverse charge: you account for the tax yourself, and invoices say so."}
599+ </p>
600+ )}
554601 <Form method="post" className="mt-4 grid gap-3 text-sm sm:grid-cols-2">
555602 <input type="hidden" name="intent" value="details" />
556603 <fieldset disabled={disabled} className="contents">
585632 </select>
586633 <input name="taxId" defaultValue={details?.taxId ?? ""} aria-label="Tax ID" className={FIELD} />
587634 </span>
635+ {details?.taxId && details.taxIdStatus && (
636+ <span className="mt-1 block text-xs text-faint">{TAX_ID_STATUS[details.taxIdStatus] ?? `Stripe's check: ${details.taxIdStatus}`}</span>
637+ )}
588638 </label>
589639 <label className="block">
590640 <span className="text-xs text-muted">Purchase order</span>
+24−1
1313 import {
1414 CAPS,
1515 CREDIT_KIND,
16+ PLUS_TAX,
1617 PREPAY,
1718 type PlanStatus,
1819 alertText,
1920 alertTone,
21+ cardFeeCents,
2022 creditLine,
2123 dollars,
2224 gigabytes,
232234 <span className="text-2xl font-semibold tabular-nums tracking-tight">${((plan?.monthlyCents ?? 2000) / 100).toFixed(0)}</span>
233235 <span className="text-sm text-muted"> / month</span>
234236 <span className="block text-xs text-faint">per workspace, never per seat</span>
237+ <span className="block text-xs text-faint">
238+ {plan?.cardFeeCents ? `+ ${dollars(plan.cardFeeCents * 10_000)} card processing fee, ${PLUS_TAX}` : "Plus tax where it applies"}
239+ </span>
235240 </p>
236241 }
237242 >
644649 );
645650 }
646651
647−export function PrepayCard({ prepaidMicros, owner, live, error }: { prepaidMicros: number; owner: boolean; live: boolean; error?: string }) {
652+export function PrepayCard({
653+ prepaidMicros,
654+ owner,
655+ live,
656+ cardFee,
657+ error,
658+}: {
659+ prepaidMicros: number;
660+ owner: boolean;
661+ live: boolean;
662+ /** The card fee as billing charges it, to show it before paying. */
663+ cardFee?: { on: boolean; percentMicros: number; fixedCents: number } | null;
664+ error?: string;
665+}) {
666+ const fees = PREPAY.presets.map((amount) => `${dollars(cardFeeCents(amount * 100, cardFee) * 10_000)} on ${wholeDollars(amount * 1_000_000)}`);
648667 return (
649668 <Card
650669 id="prepay"
685704 By bank transfer (from {wholeDollars(PREPAY.bankFrom * 1_000_000)}; counted when it arrives)
686705 </label>
687706 </RadioGroup>
707+ <p className="text-xs text-faint">
708+ {cardFee?.on ? `By card, a card processing fee is its own line (${fees.join(", ")}); a bank transfer has none. ` : ""}
709+ Tax is added where it applies, from your billing address; what you prepay is credited in full.
710+ </p>
688711 {!live && <p className="text-xs text-faint">Test mode: card 4242 4242 4242 4242, any future date and code.</p>}
689712 <ErrorText>{error}</ErrorText>
690713 </Form>
+47−0
1+/**
2+ * What a free workspace may not do, and the way forward: a free workspace
3+ * adds no one (members, invites, outside collaborators) until it starts the
4+ * plan, and a person owns at most one free workspace. Identity refuses both
5+ * either way; these say so before anyone tries.
6+ */
7+import { Sparkles } from "lucide-react";
8+
9+import { ButtonLink } from "./ui";
10+
11+/** Where a workspace's plan is started. */
12+export function planHref(workspace: string): string {
13+ return `/${workspace}/-/billing#plan`;
14+}
15+
16+/** "Start the plan to invite people", with the button, for a free workspace's owners. */
17+export function StartPlanToInvite({
18+ workspace,
19+ owner,
20+ outside = false,
21+}: {
22+ workspace: string;
23+ owner: boolean;
24+ /** On a repository's Access page: members can still be given roles. */
25+ outside?: boolean;
26+}) {
27+ return (
28+ <div role="note" className="rounded-xl border border-accent/30 bg-accent/5 p-4">
29+ <div className="flex flex-col gap-3 sm:flex-row sm:items-center">
30+ <Sparkles size={16} className="hidden shrink-0 text-accent sm:block" aria-hidden />
31+ <div className="min-w-0 grow">
32+ <p className="text-sm font-medium">Start the plan to invite people</p>
33+ <p className="mt-1 text-sm text-muted">
34+ {workspace} is a free workspace, so it cannot add people
35+ {outside ? " from outside it. Its members can still be given a role here." : ". Its members stay as they are."}{" "}
36+ {owner ? "The plan is for everyone in the workspace at one price, never per person." : "An owner can start it."}
37+ </p>
38+ </div>
39+ {owner && (
40+ <span className="shrink-0">
41+ <ButtonLink to={planHref(workspace)}>Start the plan</ButtonLink>
42+ </span>
43+ )}
44+ </div>
45+ </div>
46+ );
47+}
+19−2
141141 </dl>
142142 )}
143143
144+ {((totals.taxMicros ?? 0) !== 0 || (totals.cardFeeMicros ?? 0) !== 0) && (
145+ <p className="mt-2 text-xs text-faint">
146+ Paid with this month's payments on top of what they credited: tax {dollars(totals.taxMicros ?? 0)}, card processing fees{" "}
147+ {dollars(totals.cardFeeMicros ?? 0)}. Prices exclude tax; neither comes from your balance.
148+ </p>
149+ )}
144150 {((totals.covered?.length ?? 0) > 0 || (totals.carriedMicros ?? 0) > 0) && (
145151 <ul className="mt-2 space-y-1 rounded-xl border border-line bg-surface px-4 py-3 text-sm">
146152 {totals.covered?.map((paid) => (
174180 <span className="font-mono tabular-nums text-faint">{charge(g.chargedMicros)}</span>
175181 </div>
176182 <ul className="divide-y divide-line">
177− {g.lines.map((line) => (
183+ {g.lines.map((line) =>
184+ line.kind === "Tax" || line.kind === "Card processing fees" ? (
185+ // Paid with the day's payments, on top of what reached the balance: never charged.
186+ <li key={line.kind} className="flex items-center gap-3 px-4 py-3 text-sm">
187+ <span className="w-3.5 shrink-0" />
188+ <span className="grow truncate text-muted">
189+ {line.kind} <span className="text-xs text-faint">· paid with the payment, not from the balance</span>
190+ </span>
191+ <span className="w-24 shrink-0 text-right font-mono tabular-nums text-muted">{dollars(line.passedMicros ?? 0)}</span>
192+ </li>
193+ ) : (
178194 <StatementLineRow
179195 key={line.kind}
180196 slug={slug}
186202 day={group === "day" ? g.key : null}
187203 project={group === "project" ? g.key : null}
188204 />
189− ))}
205+ ),
206+ )}
190207 {(g.discountMicros ?? 0) > 0 && (
191208 <li className="flex items-center gap-3 px-4 py-3 text-sm">
192209 <span className="w-3.5 shrink-0" />
+20−0
88 alertText,
99 alertTone,
1010 cardCheckResult,
11+ cardFeeCents,
12+ feeAndTax,
1113 creditLine,
1214 dollars,
1315 needsAttention,
3537 assert.equal(creditLine({ ...grant, state: "revoked", leftMicros: 0 }, now), "$25.00 credit, withdrawn");
3638 });
3739
40+test("the card fee shown before paying is the one billing charges, and prices exclude tax", () => {
41+ const fee = { on: true, percentMicros: 29_000, fixedCents: 30 };
42+ // The same figures as billing's own tests (ai.rs, tax.rs).
43+ assert.equal(cardFeeCents(2_500, fee), 106);
44+ assert.equal(cardFeeCents(2_000, fee), 91);
45+ assert.equal(cardFeeCents(2_000, { ...fee, on: false }), 0);
46+ assert.equal(cardFeeCents(0, fee), 0);
47+ assert.equal(cardFeeCents(2_000, null), 0);
48+ assert.equal(feeAndTax(59), "Card processing fee $0.59, plus tax where it applies");
49+ assert.equal(feeAndTax(0), "Plus tax where it applies");
50+});
51+
3852 test("money reads as dollars", () => {
3953 assert.equal(dollars(9_500_000), "$9.50");
4054 assert.equal(dollars(-1_250_000), "−$1.25");
305319 assert.equal(parsed.value.address.country, "DE");
306320 form.set("taxId", "");
307321 assert.equal(parseInvoiceDetails(form).ok, false);
322+ // Tax is worked out from the address: in the US, the ZIP code is needed.
323+ form.set("taxIdType", "");
324+ form.set("country", "us");
325+ assert.equal(parseInvoiceDetails(form).ok, false);
326+ form.set("postalCode", "94107");
327+ assert.ok(parseInvoiceDetails(form).ok);
308328 });
+23−0
2323 return `${sign}$${abs.toLocaleString("en-US", { minimumFractionDigits: digits, maximumFractionDigits: digits })}`;
2424 }
2525
26+/** Prices on g1t exclude tax; Stripe adds it at checkout from the billing address. */
27+export const PLUS_TAX = "plus tax where it applies";
28+
29+/**
30+ * The card processing fee on a card payment of `cents`, as billing works it
31+ * out (`ai::card_fee_cents`): Stripe's percent and fixed fee grossed up, so
32+ * what is left after Stripe's fee is the amount, rounded up to the cent.
33+ * 0 when the fee is off.
34+ */
35+export function cardFeeCents(cents: number, fee: { on: boolean; percentMicros: number; fixedCents: number } | null | undefined): number {
36+ if (!fee?.on || !(cents > 0)) return 0;
37+ const rate = fee.percentMicros / MICROS_PER_DOLLAR;
38+ if (!(rate >= 0 && rate < 0.5)) return 0;
39+ return Math.max(0, Math.ceil((cents + fee.fixedCents) / (1 - rate)) - cents);
40+}
41+
42+/** "Card processing fee $1.06, plus tax where it applies", as shown before paying. */
43+export function feeAndTax(feeCents: number): string {
44+ return feeCents > 0 ? `Card processing fee ${dollars(feeCents * 10_000)}, ${PLUS_TAX}` : `Plus tax where it applies`;
45+}
46+
2647 /** A form's dollar amount as micros, or null when it is empty or not a number. */
2748 export function readDollars(value: FormDataEntryValue | null | undefined): number | null {
2849 const text = String(value ?? "").replace(/[$,\s]/g, "");
428449 if (email && !/^[^\s@]+@[^\s@]+$/.test(email)) return { ok: false, error: "That is not an email address." };
429450 const country = text("country").toUpperCase();
430451 if (country && !/^[A-Z]{2}$/.test(country)) return { ok: false, error: "The country is two letters, such as US or DE." };
452+ // Stripe Tax places a US customer by ZIP code: without it, tax cannot be worked out.
453+ if (country === "US" && !text("postalCode")) return { ok: false, error: "Add the ZIP code: in the US, tax is worked out from it." };
431454 const taxIdType = text("taxIdType");
432455 const taxId = text("taxId");
433456 if (Boolean(taxIdType) !== Boolean(taxId)) return { ok: false, error: "Give the tax ID's kind and its number together." };
+27−4
113113 },
114114 {
115115 title: "No seats, ever",
116− body: "Add as many people and agents as you like. A workspace pays one flat price for the plan, and for what it uses past what the plan includes.",
116+ body: "Once a workspace is on the plan, add as many people and agents as you like. It pays one flat price for the plan, and for what it uses past what the plan includes.",
117+ },
118+ {
119+ title: "Prices exclude tax",
120+ body: "Every price here is before tax. Stripe adds sales tax, VAT or GST where it applies, worked out from the billing address, and shows it as its own line before you pay and on every receipt and invoice. A valid business tax ID is applied where the law says so.",
121+ },
122+ {
123+ title: "Card fees are passed on, nothing more",
124+ body: "Paying by card adds Stripe's card processing fee as its own line, shown before you pay, so the 20% is never spent on fees. A bank transfer or invoiced billing has no card fee.",
117125 },
118126 ];
119127
178186 note: "Custom patterns, validity checks, code scanning, dependency review and the security overview on private repositories are the Security and quality activation. On public repositories they are free.",
179187 },
180188 { what: "Single sign-on", free: "On every plan, once it is built", plan: "On every plan, once it is built" },
181− { what: "Members", free: "Unlimited", plan: "Unlimited" },
182189 {
190+ what: "Members",
191+ free: "Only the people already in it: a free workspace cannot add members, invite people or invite outside collaborators",
192+ plan: "Unlimited, never per seat",
193+ note: "Each person can own one free workspace. More workspaces need the plan.",
194+ },
195+ {
183196 what: "Usage past what is included",
184197 free: "Not possible: a free workspace never runs up a bill",
185198 plan: "Charged at cost plus 20%, up to a spend limit you set. No quotas: only your limit stops anything.",
203216 <h1 className="mt-2 text-3xl font-semibold tracking-tight sm:text-4xl">One plan, and usage at cost plus 20%</h1>
204217 <p className="mt-3 max-w-2xl text-muted">
205218 The forge is free for everyone. Work that runs on g1t's machines is metered at what it costs g1t, plus 20%. The
206− numbers on this page are the live price book g1t charges from.
219+ numbers on this page are the live price book g1t charges from. Prices exclude tax, which is added where it applies.
207220 </p>
208221 {free && (
209222 <div className="mt-5 rounded-xl border border-accent/30 bg-accent/5 px-4 py-3 text-sm">
218231 <p>
219232 <span className="text-3xl font-semibold tabular-nums">${price}</span>{" "}
220233 <span className="text-sm text-muted">a month per workspace</span>
234+ <span className="block text-right text-xs text-faint">
235+ {plan.cardFeeCents ? `+ $${(plan.cardFeeCents / 100).toFixed(2)} card processing fee, plus tax where it applies` : "Plus tax where it applies"}
236+ </span>
221237 </p>
222238 </div>
223239 <ul className="mt-4 space-y-1.5 text-sm text-muted">
258274 <p>
259275 <span className="text-3xl font-semibold tabular-nums">${(securityPlan.monthlyCents / 100).toFixed(securityPlan.monthlyCents % 100 ? 2 : 0)}</span>{" "}
260276 <span className="text-sm text-muted">a month per workspace</span>
277+ <span className="block text-right text-xs text-faint">
278+ {securityPlan.cardFeeCents
279+ ? `+ $${(securityPlan.cardFeeCents / 100).toFixed(2)} card processing fee, plus tax where it applies`
280+ : "Plus tax where it applies"}
281+ </span>
261282 </p>
262283 </div>
263284 <p className="mt-2 text-sm text-muted">
525546 <tr>
526547 <td className="px-4 py-3">
527548 <p className="font-medium">Card processing fee</p>
528− <p className="text-xs text-faint">On AI credit bought by card, as its own line at checkout; never on invoices</p>
549+ <p className="text-xs text-faint">
550+ On every card payment, as its own line shown before you pay; never on bank transfers or invoiced billing
551+ </p>
529552 </td>
530553 <td className="px-4 py-3 text-muted">Stripe's fee</td>
531554 <td className="hidden px-4 py-3 tabular-nums sm:table-cell">—</td>
+9−3
1717 import type { Route } from "./+types/settings-access";
1818 import { RoleSelect, RolesTable } from "../../components/access";
1919 import { RepoSettingsHeading } from "../../components/repo-settings-heading";
20+import { StartPlanToInvite } from "../../components/start-plan";
2021 import { SettingsSection as Section } from "../../components/settings-section";
2122 import { Avatar, Button, ErrorText, Field, Input, SubmitButton } from "../../components/ui";
2223 import { Badge } from "../../components/ui/badge";
3233 } from "../../components/ui/alert-dialog";
3334 import { page } from "../../lib/meta";
3435 import { refusal, requireInsider } from "../../lib/access.server";
35−import { identity } from "../../lib/services.server";
36+import { billing, identity } from "../../lib/services.server";
3637 import { assertSameOrigin, requireUser, roleIn, unwrap } from "../../lib/session.server";
3738
3839 export function meta({ params, ...args }: Route.MetaArgs) {
4647 const manage = access.can.manage_access;
4748 // The workspace's teams, for Add team: only Admins add one, and a
4849 // failure there leaves the rest of the page as it is.
49− const [found, teams] = await Promise.all([
50+ const [found, teams, free] = await Promise.all([
5051 identity.repoAccess(params.owner, params.repo, viewer),
5152 manage ? identity.listTeams(viewer, params.owner).catch(() => null) : Promise.resolve(null),
53+ // A free workspace invites no one from outside; identity refuses it
54+ // either way, so a failure here only hides the note.
55+ manage ? billing.freeWorkspaces([params.owner]).catch(() => [] as string[]) : Promise.resolve([] as string[]),
5256 ]);
5357 return {
5458 access: unwrap(found),
5559 teams: teams?.ok ? teams.value : ([] as Team[]),
5660 manage,
61+ free: free.includes(params.owner.toLowerCase()),
5762 // Owners change the base permission, on the workspace's People page.
5863 owner: roleIn(viewer, params.owner) === "owner",
5964 };
143148 };
144149
145150 export default function RepoAccessSettings({ loaderData, actionData, params }: Route.ComponentProps) {
146− const { access, manage, owner, teams } = loaderData;
151+ const { access, manage, owner, teams, free } = loaderData;
147152 const base = `/${params.owner}/${params.repo}`;
148153 const full = `${params.owner}/${params.repo}`;
149154 const pending = access.invitations.filter((invitation) => invitation.status === "pending");
195200 title="Add people"
196201 about="A member of the workspace gets the role at once. Anyone else gets an invitation, by email, and has the role once they accept it."
197202 >
203+ {free && <StartPlanToInvite workspace={params.owner} owner={owner} outside />}
198204 <AddForm result={result} />
199205 </Section>
200206 )}
+48−3
316316 {notice && <p className="mb-6 rounded-lg border border-accent/30 bg-accent/5 px-4 py-2.5 text-sm">{notice}</p>}
317317 {problem && <p className="mb-6 rounded-lg border border-danger/40 bg-danger/5 px-4 py-2.5 text-sm">{problem}</p>}
318318
319+ <Suspense fallback={null}>
320+ <Await resolve={details}>
321+ {(loaded) =>
322+ loaded?.taxAddressNeededAt ? (
323+ <div role="alert" className="mb-6 rounded-xl border border-warn/40 bg-warn/5 p-4 text-sm">
324+ <p className="font-medium">Add a billing address</p>
325+ <p className="mt-1 text-muted">
326+ Stripe needs it to work out tax, so g1t did not charge the card. Nothing is lost: the charge goes through once the
327+ address is saved.{" "}
328+ {owner ? (
329+ <a href="#details" className="text-fg underline underline-offset-2">
330+ Add it under Invoice details
331+ </a>
332+ ) : (
333+ "An owner adds it under Invoice details."
334+ )}
335+ </p>
336+ </div>
337+ ) : null
338+ }
339+ </Await>
340+ </Suspense>
319341 {entitlements && <SpikeBanner slug={slug} entitlements={entitlements} owner={owner} />}
320342 {err("spike") && <p className="mb-6 text-sm text-danger">{err("spike")}</p>}
321343 <Alerts alerts={entitlements?.alerts ?? []} />
335357 <SpendLimitCard limit={limit} owner={owner} error={err("limit")} />
336358 <BudgetAlerts limit={limit} owner={owner} error={err("budget")} />
337359 <RaiseCard requests={requests} owner={owner} error={err("raise")} />
338− <PrepayCard prepaidMicros={prepaid} owner={owner} live={status.live || !staff} error={err("prepay")} />
360+ <PrepayCard prepaidMicros={prepaid} owner={owner} live={status.live || !staff} cardFee={ai?.cardFee ?? null} error={err("prepay")} />
339361 </>
340362 )}
341363
395417 Each month closes with an itemised invoice. No card is charged less than{" "}
396418 {dollars(entitlements?.minChargeMicros ?? 5 * MICROS_PER_DOLLAR, 0)}; less carries over.
397419 </li>
398− <li>No seats: add as many people and agents as you like.</li>
420+ <li>
421+ Prices exclude tax. Stripe adds tax where it applies, worked out from the billing address under Invoice details, and it
422+ is its own line on every receipt and invoice.
423+ </li>
424+ <li>
425+ Card payments carry Stripe's card processing fee as their own line, shown before you pay. Bank transfers and invoiced
426+ billing have none.
427+ </li>
428+ <li>No seats: add as many people and agents as you like, once the workspace is on the plan.</li>
399429 </ul>
400430 <div className="mt-4 space-y-1.5 border-t border-line pt-4 text-sm">
401431 <Link to={`/${slug}/-/usage`} className="flex items-center gap-2 text-muted hover:text-fg">
419449 return (
420450 <section className="mb-10">
421451 <h2 className="font-medium">Usage invoices</h2>
422− <p className="mt-1 text-sm text-muted">One when each month closes, and one each time g1t charges the card near your limit.</p>
452+ <p className="mt-1 text-sm text-muted">
453+ One when each month closes, and one each time g1t charges the card near your limit. Amounts are for usage; the card fee
454+ and tax are their own lines.
455+ </p>
423456 <ul className="mt-4 divide-y divide-line overflow-hidden rounded-xl border border-line">
424457 {invoices.map((invoice) => (
425458 <li key={invoice.invoiceId} className="px-4 py-3 text-sm">
453486 <span className="font-mono tabular-nums">{dollars(line.amountMicros)}</span>
454487 </li>
455488 ))}
489+ {(invoice.feeMicros ?? 0) > 0 && (
490+ <li className="flex justify-between gap-4">
491+ <span>Card processing fee</span>
492+ <span className="font-mono tabular-nums">{dollars(invoice.feeMicros ?? 0)}</span>
493+ </li>
494+ )}
495+ {(invoice.taxMicros ?? 0) > 0 && (
496+ <li className="flex justify-between gap-4">
497+ <span>Tax</span>
498+ <span className="font-mono tabular-nums">{dollars(invoice.taxMicros ?? 0)}</span>
499+ </li>
500+ )}
456501 </ul>
457502 </li>
458503 ))}
+90−33
1−import { Form, redirect } from "react-router";
1+import { Form, Link, redirect } from "react-router";
22
33 import type { Route } from "./+types/new";
44 import { page } from "../../lib/meta";
5−import { ErrorText, Field, Input, SubmitButton } from "../../components/ui";
6−import { identity } from "../../lib/services.server";
5+import { planHref } from "../../components/start-plan";
6+import { ButtonLink, ErrorText, Field, Input, SubmitButton } from "../../components/ui";
7+import { billing, identity } from "../../lib/services.server";
78 import { assertSameOrigin, nextPath, requireUser } from "../../lib/session.server";
89
910 export function meta(args: Route.MetaArgs) {
1011 return page(args, { title: "New workspace · g1t" });
1112 }
1213
13−export function loader({ request, context }: Route.LoaderArgs) {
14+export async function loader({ request, context }: Route.LoaderArgs) {
1415 const user = requireUser(context, request);
15− return { user, first: (user.workspaces ?? []).length === 0 };
16+ const owned = (user.workspaces ?? []).filter((membership) => membership.role === "owner").map((membership) => membership.slug);
17+ // A person owns at most one free workspace; identity refuses a second
18+ // either way, so a failure here only leaves the form up.
19+ const free = owned.length > 0 ? await billing.freeWorkspaces(owned).catch(() => [] as string[]) : [];
20+ return { user, first: (user.workspaces ?? []).length === 0, free };
1621 }
1722
1823 export async function action({ request, context }: Route.ActionArgs) {
3439 loaderData,
3540 actionData,
3641 }: Route.ComponentProps) {
37− const { user, first } = loaderData;
42+ const { user, first, free } = loaderData;
3843 return (
3944 <main className="mx-auto max-w-lg px-4 py-12">
4045 <h1 className="text-xl font-semibold">
4752 address: <span className="font-mono text-fg">g1t.sh/workspace/repo</span>.
4853 Use one for yourself, and one for each team or company you work with.
4954 </p>
50− {!user.verified && (
51− <p className="mt-4 rounded-md border border-warn/30 bg-warn/10 px-3 py-2 text-sm">
52− Confirm your email address first. We sent you a link.
53− </p>
55+ {free.length > 0 ? (
56+ <OneFreeWorkspace free={free} />
57+ ) : (
58+ <>
59+ {!user.verified && (
60+ <p className="mt-4 rounded-md border border-warn/30 bg-warn/10 px-3 py-2 text-sm">
61+ Confirm your email address first. We sent you a link.
62+ </p>
63+ )}
64+ <Form method="post" className="mt-8 space-y-4">
65+ <Field
66+ label="Name in URLs"
67+ hint="Lowercase letters, digits and single hyphens. An owner can change it later; old addresses redirect for 90 days."
68+ >
69+ <div className="flex items-center gap-2 font-mono text-sm">
70+ <span className="text-muted">g1t.sh/</span>
71+ <Input
72+ name="slug"
73+ required
74+ autoFocus
75+ maxLength={39}
76+ defaultValue={first ? user.username : ""}
77+ pattern="[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9]))*"
78+ />
79+ </div>
80+ </Field>
81+ <Field label="Display name (optional)">
82+ <Input name="displayName" maxLength={80} />
83+ </Field>
84+ <p className="text-xs text-faint">
85+ A new workspace is free. Each person can own one free workspace; more need the plan on the ones you have.
86+ </p>
87+ <ErrorText>{actionData?.error}</ErrorText>
88+ <SubmitButton pending="Creating…">Create workspace</SubmitButton>
89+ </Form>
90+ </>
5491 )}
55− <Form method="post" className="mt-8 space-y-4">
56− <Field
57− label="Name in URLs"
58− hint="Lowercase letters, digits and single hyphens. An owner can change it later; old addresses redirect for 90 days."
59− >
60− <div className="flex items-center gap-2 font-mono text-sm">
61− <span className="text-muted">g1t.sh/</span>
62− <Input
63− name="slug"
64− required
65− autoFocus
66− maxLength={39}
67− defaultValue={first ? user.username : ""}
68− pattern="[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9]))*"
69− />
70− </div>
71− </Field>
72− <Field label="Display name (optional)">
73− <Input name="displayName" maxLength={80} />
74− </Field>
75− <ErrorText>{actionData?.error}</ErrorText>
76− <SubmitButton pending="Creating…">Create workspace</SubmitButton>
77− </Form>
7892 </main>
7993 );
8094 }
95+
96+/** Why there is no form: the person owns a free workspace already. */
97+function OneFreeWorkspace({ free }: { free: string[] }) {
98+ const [first] = free;
99+ return (
100+ <section className="mt-8 rounded-xl border border-line bg-surface p-5">
101+ <h2 className="font-medium">You already own a free workspace</h2>
102+ <p className="mt-2 text-sm text-muted">
103+ Each person can own one workspace that is not on the g1t plan.{" "}
104+ {free.length === 1 ? (
105+ <>
106+ Yours is <span className="font-mono text-fg">{first}</span>.
107+ </>
108+ ) : (
109+ <>
110+ You own {free.length} from before (
111+ {free.map((slug, i) => (
112+ <span key={slug}>
113+ {i > 0 && ", "}
114+ <span className="font-mono text-fg">{slug}</span>
115+ </span>
116+ ))}
117+ ), and keep them all.
118+ </>
119+ )}{" "}
120+ A new workspace starts free, so to make one, start the plan on {free.length === 1 ? "it" : "each of them"}, or delete{" "}
121+ {free.length === 1 ? "it" : "the ones"} you no longer use.
122+ </p>
123+ <div className="mt-4 flex flex-wrap items-center gap-3">
124+ <ButtonLink to={planHref(first)}>Start the plan on {first}</ButtonLink>
125+ <Link to={`/${first}/-/settings`} className="text-sm text-muted hover:text-fg">
126+ Workspace settings
127+ </Link>
128+ </div>
129+ <p className="mt-4 text-xs text-faint">
130+ The plan is one price for everyone in the workspace, never per person.{" "}
131+ <Link to="/pricing" className="underline underline-offset-2 hover:text-fg">
132+ Pricing
133+ </Link>
134+ </p>
135+ </section>
136+ );
137+}
+31−11
1717 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../components/ui/select";
1818 import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../components/ui/tabs";
1919 import { inviteLink, inviteState, moreInvitesMailto } from "../../lib/invites";
20−import { identity } from "../../lib/services.server";
20+import { billing, identity } from "../../lib/services.server";
21+import { StartPlanToInvite } from "../../components/start-plan";
2122 import {
2223 assertSameOrigin,
2324 getViewer,
3738 // someone a repository is shared with, gets nothing here.
3839 if (!role) throw data(null, { status: 404 });
3940 const owner = role === "owner";
40− const [members, invites, workspace, outside, teams] = await Promise.all([
41+ const [members, invites, workspace, outside, teams, free] = await Promise.all([
4142 identity.listMembers(params.owner, viewer),
4243 owner ? identity.workspaceInvites(params.owner, viewer).catch(() => null) : null,
4344 identity.getWorkspace(params.owner),
4445 owner ? identity.outsideCollaborators(viewer, params.owner).catch(() => null) : null,
4546 // Each member's teams, as the viewer may see them.
4647 identity.teamMemberships(viewer, params.owner).catch(() => null),
48+ // A free workspace adds no one until it starts the plan; identity
49+ // refuses it either way, so a failure here only hides the note.
50+ billing.freeWorkspaces([params.owner]).catch(() => [] as string[]),
4751 ]);
4852 return {
4953 role,
54+ free: free.includes(params.owner.toLowerCase()),
5055 members: unwrap(members),
5156 invites: invites?.ok ? invites.value : [],
5257 base: workspace?.basePermission ?? DEFAULT_BASE_PERMISSION,
9398 };
9499
95100 export default function WorkspacePeople({ loaderData, actionData, params }: Route.ComponentProps) {
96− const { role, members, invites, origin, base, outside, teams } = loaderData;
101+ const { role, members, invites, origin, base, outside, teams, free } = loaderData;
97102 const owner = role === "owner";
98103 const pending = invites.filter((invite) => invite.status === "pending");
99104 const [search, setSearch] = useSearchParams();
144149 </li>
145150 ))}
146151 </ul>
147− {owner && (
152+ {owner && free && (
153+ <div className="mt-6">
154+ <StartPlanToInvite workspace={params.owner} owner={owner} />
155+ </div>
156+ )}
157+ {owner && !free && (
148158 // Empty again once the person is on the list; kept as typed when it failed.
149159 <Form
150160 method="post"
248258 <OutsideCollaborators
249259 people={outside}
250260 slug={params.owner}
261+ free={free}
251262 error={actionData && "converting" in actionData && actionData.converting ? actionData.error : null}
252263 />
253264 </TabsContent>
322333 function OutsideCollaborators({
323334 people,
324335 slug,
336+ free,
325337 error,
326338 }: {
327339 people: Route.ComponentProps["loaderData"]["outside"];
328340 slug: string;
341+ free: boolean;
329342 error: string | null | undefined;
330343 }) {
331344 return (
334347 People given a role on one or more of {slug}'s repositories without being members. They see only those
335348 repositories. Change or take away a role on the repository's Access settings.
336349 </p>
350+ {free && (
351+ <div className="mb-4">
352+ <StartPlanToInvite workspace={slug} owner />
353+ </div>
354+ )}
337355 {people.length === 0 ? (
338356 <div className="rounded-xl border border-dashed border-line px-6 py-10 text-center">
339357 <Users size={18} className="mx-auto text-faint" />
352370 </Link>
353371 {person.name && <span className="ml-2 text-sm text-muted">{person.name}</span>}
354372 </div>
355− <Form method="post">
356− <input type="hidden" name="action" value="convert" />
357− <input type="hidden" name="member" value={person.username} />
358− <SubmitButton variant="quiet" match={{ action: "convert", member: person.username }} pending="Converting…">
359− Convert to member
360− </SubmitButton>
361− </Form>
373+ {!free && (
374+ <Form method="post">
375+ <input type="hidden" name="action" value="convert" />
376+ <input type="hidden" name="member" value={person.username} />
377+ <SubmitButton variant="quiet" match={{ action: "convert", member: person.username }} pending="Converting…">
378+ Convert to member
379+ </SubmitButton>
380+ </Form>
381+ )}
362382 </div>
363383 <ul className="mt-2 flex flex-wrap gap-1.5 pl-10">
364384 {person.repos.map((grant) => (
+9−1
1414 const month = new URL(request.url).searchParams.get("month");
1515 const statement = await billing.statement(params.owner, viewer, month, "day");
1616 if (!statement.ok) throw data(null, { status: 404 });
17− const kinds = [...new Set(statement.value.groups.flatMap((group) => group.lines.map((line) => line.kind)))];
17+ // Tax and card fees are paid with payments, not ledger entries: a row a day each.
18+ const passed = new Set(["Tax", "Card processing fees"]);
19+ const kinds = [...new Set(statement.value.groups.flatMap((group) => group.lines.map((line) => line.kind)))].filter((kind) => !passed.has(kind));
1820 const rows: string[][] = [
1921 [
2022 "date",
4749 if (entries.value.length < 50) break;
4850 }
4951 }
52+ for (const group of statement.value.groups) {
53+ for (const line of group.lines.filter((l) => passed.has(l.kind))) {
54+ const amount = ((line.passedMicros ?? 0) / MICROS_PER_DOLLAR).toFixed(6);
55+ rows.push([group.key, line.kind, "Paid with the day's payments, not from the balance", "", "", "", "", "", "", amount, "", "", "", ""]);
56+ }
57+ }
5058 const body = [rows[0], ...rows.slice(1).sort((a, b) => a[0].localeCompare(b[0]))].map((r) => r.map(cell).join(",")).join("\r\n");
5159 return new Response(`${body}\r\n`, {
5260 headers: {
+78−3
17191719 pub by: String,
17201720 }
17211721
1722+/// `admin_enterprise_address`: the enterprise's billing address and tax ID,
1723+/// saved on its Stripe customer (made by `admin_enterprise_billing`).
1724+/// Stripe Tax works its invoices' tax out from the address; an invoice is
1725+/// not sent without one. Returns `Outcome<bool>`.
1726+#[derive(Debug, Serialize, Deserialize)]
1727+#[serde(rename_all = "camelCase")]
1728+pub struct AdminEnterpriseAddressArgs {
1729+ pub id: String,
1730+ pub address: PostalAddress,
1731+ #[serde(default, alias = "tax_id_type")]
1732+ pub tax_id_type: Option<String>,
1733+ #[serde(default, alias = "tax_id")]
1734+ pub tax_id: Option<String>,
1735+ pub by: String,
1736+}
1737+
17221738 /// `admin_invoice_enterprise`: sends an enterprise its invoice now, for
17231739 /// what its workspaces owe, rather than waiting for the month to close.
17241740 /// Returns `Outcome<EnterpriseInvoice>`.
17681784 pub pdf_url: Option<String>,
17691785 pub lines: Vec<InvoiceItem>,
17701786 pub created_at: String,
1787+ /// The card processing fee on top of `amount_micros`, when the invoice
1788+ /// is charged to a card; never part of the usage it pays for.
1789+ #[serde(default)]
1790+ pub fee_micros: i64,
1791+ /// The tax Stripe added on top, once it is known (after paying).
1792+ #[serde(default)]
1793+ pub tax_micros: i64,
17711794 }
17721795
17731796 #[derive(Clone, Debug, Serialize, Deserialize)]
18551878 /// What the account's discount took off the line's price.
18561879 #[serde(default)]
18571880 pub discount_micros: i64,
1881+ /// On the `Tax` and `Card processing fees` lines: what was paid with
1882+ /// payments on top of what reached the balance (negative for what a
1883+ /// refund gave back). Never in `charged_micros` or the balance.
1884+ #[serde(default)]
1885+ pub passed_micros: i64,
18581886 }
18591887
18601888 #[derive(Clone, Debug, Serialize, Deserialize)]
18811909 /// carries over to the next invoice. Zero when nothing carried.
18821910 #[serde(default)]
18831911 pub carried_micros: i64,
1912+ /// Tax and card processing fees paid with the month's payments, on top
1913+ /// of `paid_micros`.
1914+ #[serde(default)]
1915+ pub tax_micros: i64,
1916+ #[serde(default)]
1917+ pub card_fee_micros: i64,
18841918 }
18851919
18861920 /// One source that paid for usage before it was charged.
24862520 pub struct Plan {
24872521 pub feature: Feature,
24882522 pub title: String,
2489− /// Charged every month while the plan is on, in cents.
2523+ /// Charged every month while the plan is on, in cents, excluding tax.
24902524 pub monthly_cents: u32,
2525+ /// The card processing fee on top each month, in cents (0 when the
2526+ /// fee is off). Excluding tax, like the price.
2527+ #[serde(default)]
2528+ pub card_fee_cents: u32,
24912529 /// What the monthly price includes, one line each, for people to read.
24922530 pub includes: Vec<String>,
24932531 /// How usage past the allowance is charged, for people to read.
26262664 pub feature: Feature,
26272665 }
26282666
2667+/// `free_workspaces`: which of `workspaces` are free, that is on no paid
2668+/// plan. Paid is the g1t plan, an enterprise's terms, or a discount of
2669+/// 100% (g1t's own workspaces). Identity asks before a workspace is made
2670+/// (a person owns at most one free workspace) and before anyone is added
2671+/// to one (a free workspace cannot invite). Returns `Vec<String>`, the
2672+/// free ones, lower-cased; none where payments are not set up.
2673+#[derive(Debug, Serialize, Deserialize)]
2674+pub struct FreeWorkspacesArgs {
2675+ pub workspaces: Vec<String>,
2676+}
2677+
26292678 /// `charge_feature`: usage of a feature past its plan's allowance, charged
26302679 /// from the workspace's credit at cost plus the margin, whatever
26312680 /// `FREE_WHILE_BUILDING` says. Called by the service that provides it.
27742823 pub cloudflare_cost_micros: i64,
27752824 #[serde(default)]
27762825 pub models_cost_micros: i64,
2826+ /// Tax collected with payments over the range, net of refunds: owed to
2827+ /// the tax authorities, never in cash or revenue.
2828+ #[serde(default)]
2829+ pub tax_collected_micros: i64,
2830+ /// Card processing fees passed on with card payments, net of refunds:
2831+ /// they pay Stripe's fee, so they are not revenue either.
2832+ #[serde(default)]
2833+ pub card_fees_micros: i64,
27772834 }
27782835
27792836 /// A count, cost or leak that does not add up.
29192976 /// and at least `anomaly_floor_micros`, is flagged.
29202977 pub anomaly_factor: f64,
29212978 pub anomaly_floor_micros: i64,
2922− /// Pass Stripe's card fee on as its own line when AI credit is bought
2923− /// by card (`card_fee_percent` and `card_fee_fixed` in the price book).
2979+ /// Pass Stripe's card fee on as its own line on every card payment (the
2980+ /// plan, Security and quality, prepaying, AI credit, auto-reload and
2981+ /// invoices charged to a card), never on a bank transfer or an invoice
2982+ /// sent to be paid (`card_fee_percent` and `card_fee_fixed` in the
2983+ /// price book). On by default.
29242984 #[serde(default = "yes")]
29252985 pub card_fee: bool,
29262986 }
35483608 /// Stripe could not be read: what is shown is what g1t keeps.
35493609 #[serde(default)]
35503610 pub unavailable: Option<String>,
3611+ /// Whether Stripe Tax can place the customer from the address: tax
3612+ /// is worked out from it, and without it nothing is charged.
3613+ #[serde(default)]
3614+ pub tax_location: bool,
3615+ /// Set when g1t did not charge for want of an address (RFC 3339).
3616+ #[serde(default)]
3617+ pub tax_address_needed_at: Option<String>,
3618+ /// Stripe's check of the tax ID: `pending`, `verified`, `unverified` or
3619+ /// `unavailable`.
3620+ #[serde(default)]
3621+ pub tax_id_status: Option<String>,
3622+ /// `none`, `exempt` or `reverse`, as staff set it at Stripe; g1t never
3623+ /// changes it.
3624+ #[serde(default)]
3625+ pub tax_exempt: Option<String>,
35513626 }
35523627
35533628 /// `set_billing_details`: saves the invoice details on the Stripe customer.
+130−1
117117 what the plan's included usage, a trial, the open-source pool or g1t paid.
118118 g1t's own (comped) workspaces are valued at cost plus the margin.
119119 - **Cash** = what workspaces paid: `-amount_micros`, and the plan's price.
120+ Never tax or card fees: a payment credits the balance, and
121+ `plan_payments`, without them (see [Tax and the card fee](#tax-and-the-card-fee)).
120122 - **Given away** = the part of the cost that went on usage g1t paid for
121123 itself on purpose, by why:
122124 - **comped**: all of a comped workspace's cost, every bucket;
501503 `token_usage` holds for the session and what the sandbox reported with its
502504 cost (`finish_run`'s `tokens`, from Claude Code's closing `usage`), each
503505 weighted by kind. **Card fee switch:** sudo → Costs → Guardrails → *Card fee
504−on AI credit bought by card* (`cost_settings.card_fee`, `on`/`off`).
506+on card payments* (`cost_settings.card_fee`, `on`/`off`, on by default). It
507+covers every card payment now, not only AI credit: see
508+[Tax and the card fee](#tax-and-the-card-fee).
505509
506510 **On a workspace's own model key** (migration `0041_agent_rate_own_key.sql`):
507511 the run keeps its model session (`runs.session_id`, `ms_…`) so the proxy's
759763 came back from; renaming a workspace (the customer's name). Nothing a page
760764 view reads.
761765
766+## Tax and the card fee
767+
768+Owner decision 2026-10-08. Code: `services/billing/src/tax.rs` (what is
769+kept, the address hold), `stripe.rs` (every request's tax fields),
770+`invoices.rs`, `webhooks.rs`, `ai.rs`; migration
771+`0043_tax_and_card_fees.sql`.
772+
773+### What Stripe is asked
774+
775+Every price excludes tax (`tax_behavior=exclusive`) and carries tax code
776+`txcd_10103001` (software as a service, business use; the card fee too,
777+since a fee for paying for a sale follows the sale). Fields are valid for
778+`2025-02-24.acacia`.
779+
780+| Request | Tax | Card fee |
781+| --- | --- | --- |
782+| Checkout, plan or Security (`subscription_fields`) | `automatic_tax[enabled]`, `billing_address_collection=required`, `tax_id_collection[enabled]`, with a customer `customer_update[address]=auto` and `[name]=auto`; the subscription keeps automatic tax for every renewal | A second recurring line, *Card processing fee* |
783+| Subscription on a saved card (`saved_subscription_fields`) | `automatic_tax[enabled]`; a customer Stripe Tax cannot place fails, and the person is sent to Checkout, which asks for the address | `items[1]`, the `card_fee` product |
784+| Checkout, prepay (`prepay_fields`) | As above | By card only; none by bank transfer |
785+| Checkout, AI credit (`credit_fields`) | As above | Its own line |
786+| Checkout, card check (`card_check_fields`) | Setup mode: nothing charged, nothing taxed. `billing_address_collection=required`, and the card's address is copied onto a customer with none (`fill_address`) | — |
787+| Auto-reload (`charge_saved`) | `POST /tax/calculations` first (credit and fee as lines), the PaymentIntent for the total, then `POST /tax/transactions/create_from_calculation` with the PaymentIntent as reference; a refund reverses its share (`create_reversal`, `mode=partial`) | In the calculation and the amount |
788+| Workspace invoice, month close and threshold (`invoice_workspace`) | `automatic_tax[enabled]` on the draft; each item `tax_behavior`, `tax_code` | An item *Card processing fee*, when the default payment method is a card |
789+| Enterprise invoice (`invoice_enterprise`) | The same | Never |
790+| Products (`Stripe::product`) | Made with `tax_code`; one found without it is given it | The `card_fee` product, `metadata[g1t]=card_fee` |
791+
792+### What is kept
793+
794+A payment credits the balance with what it paid for, never its tax or fee:
795+prepay credits the page's `amount_subtotal` less the fee line
796+(`credit_prepayment`), a workspace invoice `amount_paid − tax − fee`
797+(`credit_invoice`), AI credit its credit amount, and `plan_payments` the
798+plan's invoice less its tax and *Card processing fee* lines
799+(`stripe::invoice_split`). Each payment's tax and fee are rows in
800+`tax_and_fees` (`<reference>/tax`, `<reference>/card_fee`; the enterprise's
801+account id in `workspace` for its invoices), with the PaymentIntent, so a
802+refund (`charge.refunded`) gives back the balance, tax and fee in
803+proportion (`tax::refund_split`, negative rows under `refund/<charge>/…`).
804+`workspace_invoices.fee_micros` and `tax_micros` sit beside each usage
805+invoice.
806+
807+- **Statement.** *Tax* and *Card processing fees* are their own lines per
808+ day (`StatementLine.passed_micros`), never in `charged_micros`; totals
809+ `tax_micros`, `card_fee_micros`. The CSV has a row a day for each.
810+- **Margin.** Cash never holds them, so margin is untouched. sudo → Costs
811+ shows **Tax collected** and **Card fees passed on** for the range
812+ (`OverallMargin.tax_collected_micros`, `card_fees_micros`). Tax is owed to
813+ the authorities: file it from Stripe Tax's reports, never from g1t's.
814+
815+### No address
816+
817+Stripe Tax needs a country (in the US a ZIP code, in Canada a postal code
818+or province: `stripe::address_places_customer`). Before a workspace
819+invoice is drafted, g1t checks the customer; without an address, or when
820+Stripe leaves the draft at `requires_location_inputs` or refuses with
821+`customer_tax_location_invalid`, nothing is charged:
822+`accounts.tax_address_needed_at` is set, the owners are emailed once
823+(`notify_owners`), and Billing shows **Add a billing address**. Saving
824+Invoice details with an address Stripe Tax can use clears it, as does a
825+charge that goes through. Work is not stopped for it; the limits still
826+apply. Auto-reload without an address fails like a declined card (turned
827+off, owners told). An enterprise's invoice is not sent without an address:
828+sudo → the enterprise → Invoices → **Billing address** (`admin_enterprise_address`,
829+with its tax ID; audited `billing_address`).
830+
831+### The card fee
832+
833+`card_fee_cents` grosses Stripe's fee up so the amount paid for is left
834+after it: `(amount + 30¢) / (1 − 2.9%)`, rounded up; $0.91 on $20, $1.06
835+on $25. It is worked out on the amount before tax, so Stripe's fee on the
836+tax itself (a few cents) is g1t's. It is shown before paying: the plan card
837+and pricing page (`Plan.card_fee_cents`), AI credit (*Card processing fee
838+$1.06, plus tax where it applies*), Prepay. Never on a bank transfer or an
839+enterprise's (`send_invoice`) invoice. Meters stay at cost + 20% and models
840+at the provider's price plus the agent rate (price versions in migration
841+0040); the fee is passed through, not margin.
842+
843+### Tax-exempt customers and tax IDs
844+
845+g1t never sets `tax_exempt`. For a customer who sends an exemption
846+certificate, set it in Stripe's dashboard (Customers → the customer → Tax
847+status: Exempt, or Reverse charge); Billing then says so. Tax IDs come
848+from Checkout (`tax_id_collection`) or Invoice details (`set_billing_details`,
849+validated against Stripe's types in `details::TAX_ID_TYPES`); Stripe checks
850+EU VAT numbers and Stripe Tax applies a reverse charge where it should.
851+Billing shows Stripe's `verification.status`.
852+
853+### In Stripe's dashboard (not done by g1t)
854+
855+1. **Settings → Tax → Get started**: turn on Stripe Tax in live and test
856+ mode.
857+2. **Origin address**: Flagon, Inc.'s head office address.
858+3. **Default tax code**: Software as a service, business use
859+ (`txcd_10103001`); **default tax behavior**: exclusive.
860+4. **Registrations**: add each jurisdiction where Flagon is registered to
861+ collect (its home state at least; then states as thresholds are
862+ crossed, which Stripe Tax's monitoring flags; the EU's OSS and the UK
863+ if selling there). Stripe collects only where a registration exists.
864+5. **Customer portal**: tax ID and address updates are already allowed
865+ (`portal_configuration`).
866+6. Refund an invoice through a **credit note**, so its tax is reversed in
867+ Stripe Tax.
868+
869+## Free workspaces
870+
871+Owner decision 2026-10-08: one free workspace per person, and a free
872+workspace adds no one. Billing answers one question, `free_workspaces`
873+(`credits.rs`): which of the given workspaces are on no paid plan
874+(`plan_kind_for` is `Free`). The plan, an enterprise's terms and a 100%
875+discount (flagon-io) count as paid; with payments off nothing is free.
876+Identity asks it (`services/identity/src/paid.rs`) and refuses with
877+`payment_required`:
878+
879+| Where | Refused when |
880+| --- | --- |
881+| `create_workspace` | The person owns any free workspace. Several from before are kept (grandfathered); none can be added until each is paid for or deleted. |
882+| `add_member`, `invite_member` | The workspace is free. |
883+| `add_collaborator` | Someone outside a free workspace (a username who is not a member, or an address). Members' roles are fine. |
884+| `accept_invite`, `respond_repo_invitation` | The invite's workspace (or repository's) is free now: it waits. A sign-up with such an invite makes the account without joining. |
885+
886+`@g1t` is never counted as someone added. If billing cannot be asked, the
887+change is refused for now ("try again"), never let through. The site says
888+so first (New workspace, People, a repository's Access, from the same RPC);
889+the API and MCP pass identity's refusal on as `402`.
890+
762891 ## The Security and quality activation
763892
764893 A second monthly subscription a workspace can hold beside the plan
+30−0
989989 stops work until paid. The owner's own spend limit always means stop.
990990 Test-mode payments never lower exposure or raise trust.
991991
992+### Tax, card fees and free workspaces (built 2026-10-08)
993+
994+> **2026-10-08, decided:** Stripe Tax everywhere ("so I don't fuck up on
995+> taxes"); Stripe's card fee passed to the customer with the 20% markup
996+> kept; one free workspace per person; no invites on free workspaces.
997+
998+- **Stripe Tax on every payment.** `automatic_tax` on every Checkout page
999+ (plan, Security and quality, prepaying, AI credit), every subscription
1000+ and every invoice g1t makes (month close, threshold, enterprise), and a
1001+ tax calculation and transaction for auto-reload's off-session charge.
1002+ Tax code `txcd_10103001` (SaaS, business use), every price
1003+ `tax_behavior=exclusive`. Checkout always collects the billing address
1004+ and tax ID and saves them on the customer. Prices on g1t are shown
1005+ excluding tax. Tax is never revenue: balances and plan payments are
1006+ credited without it, it is kept in `tax_and_fees`, shown as its own
1007+ statement line, and as **Tax collected** on sudo's Costs. Without an
1008+ address g1t does not charge: the owners are asked for one.
1009+- **The card fee** (2.9% + $0.30, grossed up) is its own line on every
1010+ card payment, the plan's and Security's as a monthly item; never on a
1011+ bank transfer or an enterprise's invoice. On by default
1012+ (`cost_settings.card_fee`). Not revenue either. Meters stay at cost +
1013+ 20%; models at the provider's price plus the agent rate.
1014+- **One free workspace per person.** Identity asks billing
1015+ (`free_workspaces`) before creating one; a second is refused with the
1016+ way forward. Those who own several from before keep them.
1017+- **A free workspace adds no one**: no members, invites or outside
1018+ collaborators until it starts the plan; its members stay; @g1t never
1019+ counts. Enforced in identity for every path (site, API, MCP).
1020+- Details: docs/BILLING_OPERATIONS.md, *Tax and the card fee*.
1021+
9921022 ### Promo codes (planned)
9931023
9941024 Staff credits (promotional, goodwill, refund; `services/billing/src/grants.rs`,
+27−1
457457 pdfUrl: string | null;
458458 lines: { description: string; amountMicros: number }[];
459459 createdAt: string;
460+ /** The card processing fee on top of `amountMicros` when charged to a card, and the tax Stripe added once known. */
461+ feeMicros?: number;
462+ taxMicros?: number;
460463 };
461464
462465 /** A month of the ledger, grouped by day or project, a line per kind of charge. */
476479 coveredMicros?: number;
477480 priceMicros?: number;
478481 discountMicros?: number;
482+ /** On `Tax` and `Card processing fees` lines: what was paid with payments on top of what reached the balance. Never charged. */
483+ passedMicros?: number;
479484 }[];
480485 chargedMicros: number;
481486 priceMicros?: number;
495500 covered?: { source: "included" | "trial" | "oss_pool" | "given" | string; label: string; micros: number }[];
496501 /** Owed when the month closed but under the minimum charge: on the next invoice. */
497502 carriedMicros?: number;
503+ /** Tax and card processing fees paid with the month's payments, on top of `paidMicros`. */
504+ taxMicros?: number;
505+ cardFeeMicros?: number;
498506 };
499507 };
500508
627635 stripe(fix?: boolean, by?: string): Promise<StripeStatus>;
628636 /** Where an enterprise's invoices go; makes its Stripe customer. */
629637 enterpriseBilling(id: string, email: string, by: string): Promise<Result<PayingAccount>>;
638+ /** The enterprise's billing address and tax ID, on its Stripe customer: Stripe Tax works its invoices out from them. */
639+ enterpriseAddress(id: string, address: PostalAddress, taxIdType: string | null, taxId: string | null, by: string): Promise<Result<boolean>>;
630640 /** Sends an enterprise its invoice now, for what its workspaces owe. */
631641 invoiceEnterprise(id: string, by: string): Promise<Result<EnterpriseInvoice>>;
632642 /** Exactly these workspaces' accounts, such as one page of the list. */
851861 export type FeaturePlan = {
852862 feature: Feature;
853863 title: string;
854− /** Charged every month while the plan is on, in cents. */
864+ /** Charged every month while the plan is on, in cents, excluding tax. */
855865 monthlyCents: number;
866+ /** The card processing fee on top each month, in cents (0 when off), excluding tax. */
867+ cardFeeCents?: number;
856868 /** What the price includes, one line each. */
857869 includes: string[];
858870 /** How usage past the allowance is charged. */
963975 confirmSubscription(workspace: string, viewer: Viewer, session: string): Promise<Result<FeatureState>>;
964976 /** Ends a plan at the end of its period, or (`resume`) takes that back. Owners only. */
965977 cancelSubscription(actor: User, workspace: string, feature: Feature, resume?: boolean): Promise<Result<FeatureState>>;
978+ /** Which of the workspaces are free (on no paid plan); none where payments are not set up. */
979+ freeWorkspaces(workspaces: string[]): Promise<string[]>;
966980 /** Whether a feature works for a workspace now; a failure with the reason when not. */
967981 hasFeature(workspace: string, feature: Feature): Promise<Result<boolean>>;
968982 /**
12371251 includedMicros?: number;
12381252 cloudflareCostMicros?: number;
12391253 modelsCostMicros?: number;
1254+ /** Tax collected with payments over the range, net of refunds: owed to tax authorities, never cash or revenue. */
1255+ taxCollectedMicros?: number;
1256+ /** Card processing fees passed on with card payments, net of refunds: they pay Stripe's fee, not revenue. */
1257+ cardFeesMicros?: number;
12401258 };
12411259
12421260 /** A count, cost or leak that does not add up. */
15731591 invoices: StripeInvoice[];
15741592 upcoming: UpcomingInvoice;
15751593 unavailable?: string | null;
1594+ /** Whether Stripe Tax can place the customer from the address; without it nothing is charged. */
1595+ taxLocation?: boolean;
1596+ /** Set when g1t did not charge for want of a billing address. */
1597+ taxAddressNeededAt?: string | null;
1598+ /** Stripe's check of the tax ID: pending, verified, unverified or unavailable. */
1599+ taxIdStatus?: string | null;
1600+ /** none, exempt or reverse, as set at Stripe. */
1601+ taxExempt?: string | null;
15761602 };
15771603
15781604 export type BillingDetailsInput = {
+2−0
471471 cancelSubscription: (actor, workspace, feature, resume = false) =>
472472 call("cancel_subscription", { actor, workspace, feature, resume }),
473473 hasFeature: (workspace, feature) => call("has_feature", { workspace, feature }),
474+ freeWorkspaces: (workspaces) => call("free_workspaces", { workspaces }),
474475 chargeFeature: (charge) => call("charge_feature", charge),
475476 billingPortal: (actor, workspace, returnUrl) => call("billing_portal", { actor, workspace, return_url: returnUrl }),
476477 recordSandbox: (usage) => call("record_sandbox", usage),
535536 billingLink: (workspace, by) => call("admin_billing_link", { workspace, by }),
536537 stripe: (fix = false, by) => call("admin_stripe", { fix, by: by ?? null }),
537538 enterpriseBilling: (id, email, by) => call("admin_enterprise_billing", { id, email, by }),
539+ enterpriseAddress: (id, address, taxIdType, taxId, by) => call("admin_enterprise_address", { id, address, taxIdType, taxId, by }),
538540 invoiceEnterprise: (id, by) => call("admin_invoice_enterprise", { id, by }),
539541 accountsFor: (workspaces) => call("admin_accounts", { query: null, workspaces }),
540542 signals: () => call("admin_signals", {}),
+51−0
1+-- Stripe Tax on every payment, and the card processing fee on every card
2+-- payment.
3+--
4+-- Prices are shown and kept excluding tax. Stripe works the tax out on
5+-- every Checkout page, subscription, invoice and off-session charge
6+-- (`automatic_tax`, tax code `txcd_10103001`, tax behavior `exclusive`).
7+-- What reaches a workspace's balance is the payment less its tax and its
8+-- card fee; neither is revenue. Each is kept here, one row per payment and
9+-- kind, so the statement shows them as their own lines and sudo's Costs
10+-- shows tax collected apart from cash.
11+
12+CREATE TABLE IF NOT EXISTS tax_and_fees (
13+ -- `<reference>/tax` or `<reference>/card_fee`. A refund's share is
14+ -- negative, under the refund's reference `refund/<charge>/<refunded>`.
15+ id TEXT PRIMARY KEY,
16+ -- The workspace, or for an enterprise's invoice its billing account.
17+ workspace TEXT NOT NULL,
18+ -- tax or card_fee.
19+ kind TEXT NOT NULL,
20+ -- Positive when collected, negative when refunded.
21+ amount_micros INTEGER NOT NULL,
22+ -- The payment: an invoice, a Checkout page or a PaymentIntent.
23+ reference TEXT NOT NULL,
24+ -- The PaymentIntent that took the money, so a refund finds its tax.
25+ payment_intent TEXT,
26+ -- Stripe Tax's transaction for an off-session charge (auto-reload),
27+ -- which a refund reverses.
28+ tax_transaction TEXT,
29+ created_at TEXT NOT NULL
30+);
31+CREATE INDEX IF NOT EXISTS tax_and_fees_by_workspace ON tax_and_fees (workspace, created_at);
32+CREATE INDEX IF NOT EXISTS tax_and_fees_by_day ON tax_and_fees (created_at);
33+CREATE INDEX IF NOT EXISTS tax_and_fees_by_intent ON tax_and_fees (payment_intent);
34+
35+-- A workspace invoice's card fee and tax, apart from the usage it pays for.
36+ALTER TABLE workspace_invoices ADD COLUMN fee_micros INTEGER NOT NULL DEFAULT 0;
37+ALTER TABLE workspace_invoices ADD COLUMN tax_micros INTEGER NOT NULL DEFAULT 0;
38+
39+-- Set when Stripe Tax could not work out where the customer is (no
40+-- billing address), so g1t did not charge: the Billing page asks an owner
41+-- for the address, and saving it clears this.
42+ALTER TABLE accounts ADD COLUMN tax_address_needed_at TEXT;
43+
44+-- The card processing fee is on for every card payment, not only AI
45+-- credit: the setting's note says so. Never on invoiced or enterprise
46+-- payments, or bank transfers.
47+INSERT OR IGNORE INTO cost_settings (key, value, updated_at, updated_by) VALUES
48+ ('card_fee', 'on', '2026-10-08T00:00:00Z', 'migration');
49+
50+INSERT OR IGNORE INTO price_changes (id, meter, old_cost_micros, new_cost_micros, markup_percent, reason, created_at) VALUES
51+ ('prc_card_fee_all_cards', 'card_fee_percent', 29000, 29000, 0, 'Stripe''s card fee (2.9% + $0.30) is passed on as its own line on every card payment: the plan, Security and quality, prepaying, AI credit and invoices charged to a card. None on bank transfers or invoiced (enterprise) billing. Prices exclude tax; tax is added where it applies', '2026-10-08T00:00:00Z');
+32−1
462462 let fee = i64::from(open.fee_cents.unwrap_or(0)) * 10_000;
463463 self.grant_purchased(&open.workspace, session_id, micros, fee, &open.created_by, session.customer.as_deref())
464464 .await?;
465+ let extras = crate::tax::Extras { tax_cents: session.tax_cents(), fee_cents: fee / 10_000 };
466+ self.record_extras(&open.workspace, session_id, session.payment_intent.as_deref(), extras, None).await?;
465467 Ok(Ok(format!("{}: {} of AI credit bought", open.workspace, cents(micros))))
466468 }
467469
733735 ])?
734736 .run()
735737 .await?;
736− let charge = crate::stripe::SavedCharge {
738+ let untaxed = crate::stripe::SavedCharge {
737739 workspace,
738740 customer: &customer,
739741 payment_method: &method.id,
740742 credit_cents,
741743 fee_cents,
744+ tax_cents: 0,
745+ tax_calculation: None,
742746 key: &key,
743747 };
748+ // No Checkout page or invoice works the tax out here: Stripe Tax's
749+ // calculation does, for the customer's saved address. Without one,
750+ // nothing is charged and the owners are asked for it.
751+ let calculation = match stripe.tax_calculation(&untaxed).await {
752+ Ok(calculation) => calculation,
753+ Err(error) if crate::stripe::is_tax_location_error(&error) => {
754+ self.tax_address_needed(workspace).await?;
755+ self.reload_failed(workspace, Some(&key), amount, "Stripe needs the workspace's billing address to work out tax; add it under Invoice details")
756+ .await?;
757+ return Ok(None);
758+ }
759+ Err(error) => return Err(error),
760+ };
761+ let tax_cents = u32::try_from(calculation.tax_amount_exclusive.max(0)).unwrap_or(0);
762+ let charge = crate::stripe::SavedCharge { tax_cents, tax_calculation: Some(&calculation.id), ..untaxed };
744763 let paid = match stripe.charge_saved(&charge).await {
745764 Ok(intent) if intent["status"].as_str() == Some("succeeded") => intent["id"].as_str().map(str::to_owned),
746765 Ok(intent) => {
761780 .run()
762781 .await?;
763782 self.grant_purchased(workspace, &intent, amount, i64::from(fee_cents) * 10_000, "g1t", Some(&customer)).await?;
783+ // Recorded with Stripe Tax once paid, so it is reported and filed;
784+ // a failure is logged and the payment stands.
785+ let transaction = match stripe.record_tax(&calculation.id, &intent).await {
786+ Ok(id) => Some(id),
787+ Err(error) => {
788+ worker::console_error!("{workspace}: the tax on auto-reload {intent} was not recorded with Stripe Tax: {error}");
789+ None
790+ }
791+ };
792+ let extras = crate::tax::Extras { tax_cents: i64::from(tax_cents), fee_cents: i64::from(fee_cents) };
793+ self.record_extras(workspace, &intent, Some(&intent), extras, transaction.as_deref()).await?;
794+ self.tax_address_given(workspace).await?;
764795 Ok(Some(amount))
765796 }
766797
+9−0
123123 return Ok(Ok("ignored: settled meanwhile".to_owned()));
124124 }
125125 let workspace = open.workspace;
126+ // The address entered with the card, onto a customer that has none,
127+ // so the plan and invoices that follow can be taxed.
128+ if let (Some(customer), Some(address)) = (session.customer.as_deref(), card.address.as_ref()) {
129+ match stripe.fill_address(customer, address).await {
130+ Ok(true) => self.tax_address_given(&workspace).await?,
131+ Ok(false) => {}
132+ Err(error) => worker::console_error!("{workspace}: the card's billing address was not saved on the customer: {error}"),
133+ }
134+ }
126135 let now = rfc3339(now_ms());
127136 #[derive(Deserialize)]
128137 struct Count {
+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

+0−0

Binary or large file; its contents are not shown.

This change is too large to show in full.