Manage calls and the inbox through the API

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 19:42:59 +02:00
parent b02464a7ed
commit 4c65604f04
11 changed files with 890 additions and 1 deletions

View File

@@ -118,6 +118,10 @@ tags:
description: What the people the collective worked with said
- name: Talks
description: Talks given elsewhere, by members of the collective
- name: Calls
description: Open calls for contributors
- name: Applications
description: The inbox — what people sent from the public site
- name: Technologies
description: What the collective uses, and its place on the tech radar
- name: Users
@@ -1997,6 +2001,206 @@ paths:
"204": { description: Deleted }
"403": { $ref: "#/components/responses/Forbidden" }
/v1/calls:
get:
tags: [Calls]
summary: List calls
parameters:
- $ref: "#/components/parameters/Lang"
- $ref: "#/components/parameters/With"
- $ref: "#/components/parameters/PerPage"
- name: status
in: query
description: "`open`, `filled` or `closed`."
schema: { type: string }
- name: project_id
in: query
schema: { type: integer }
- name: search
in: query
description: Matches the title within the active language only.
schema: { type: string }
responses:
"200":
description: Paginated calls
content:
application/json:
schema: { $ref: "#/components/schemas/CallCollection" }
"403": { $ref: "#/components/responses/Forbidden" }
post:
tags: [Calls]
summary: Create a call
description: |
`technology_ids` is replaced whole when present.
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/CallWrite" }
responses:
"201":
description: Call created
content:
application/json:
schema:
type: object
properties:
data: { $ref: "#/components/schemas/Call" }
"403": { $ref: "#/components/responses/Forbidden" }
"422": { $ref: "#/components/responses/ValidationError" }
/v1/calls/{call}:
parameters:
- name: call
in: path
required: true
schema: { type: integer }
get:
tags: [Calls]
summary: Show a call
parameters:
- $ref: "#/components/parameters/Lang"
- $ref: "#/components/parameters/With"
responses:
"200":
description: The call
content:
application/json:
schema:
type: object
properties:
data: { $ref: "#/components/schemas/Call" }
"403": { $ref: "#/components/responses/Forbidden" }
"404": { description: Not found }
patch:
tags: [Calls]
summary: Update a call
description: Partial update. Translatable fields merge into the existing map.
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/CallWrite" }
responses:
"200":
description: Call updated
content:
application/json:
schema:
type: object
properties:
data: { $ref: "#/components/schemas/Call" }
"403": { $ref: "#/components/responses/Forbidden" }
"422": { $ref: "#/components/responses/ValidationError" }
delete:
tags: [Calls]
summary: Delete a call
responses:
"204": { description: Deleted }
"403": { $ref: "#/components/responses/Forbidden" }
/v1/applications:
get:
tags: [Applications]
summary: List applications
parameters:
- $ref: "#/components/parameters/PerPage"
- name: status
in: query
description: "`new`, `contacted`, `accepted`, `declined` or `spam`. Without it, spam is left out."
schema: { type: string }
- name: kind
in: query
description: "`contribute` or `request`."
schema: { type: string }
- name: call_id
in: query
schema: { type: integer }
- name: search
in: query
description: Matches the name, e-mail or organisation.
schema: { type: string }
- name: trashed
in: query
schema: { type: boolean }
responses:
"200":
description: Paginated applications
content:
application/json:
schema: { $ref: "#/components/schemas/ApplicationCollection" }
"403": { $ref: "#/components/responses/Forbidden" }
/v1/applications/{application}:
parameters:
- name: application
in: path
required: true
schema: { type: integer }
get:
tags: [Applications]
summary: Show an application
responses:
"200":
description: The application
content:
application/json:
schema:
type: object
properties:
data: { $ref: "#/components/schemas/Application" }
"403": { $ref: "#/components/responses/Forbidden" }
"404": { description: Not found }
patch:
tags: [Applications]
summary: Handle an application
description: |
Only how it is being handled changes: `status` and the private
`notes`. Moving it to `contacted`, `accepted` or `declined` records who
did it and when; back to `new` clears both.
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/ApplicationWrite" }
responses:
"200":
description: Application updated
content:
application/json:
schema:
type: object
properties:
data: { $ref: "#/components/schemas/Application" }
"403": { $ref: "#/components/responses/Forbidden" }
"422": { $ref: "#/components/responses/ValidationError" }
delete:
tags: [Applications]
summary: Soft-delete an application
responses:
"204": { description: Deleted }
"403": { $ref: "#/components/responses/Forbidden" }
/v1/applications/{application}/restore:
post:
tags: [Applications]
summary: Restore a soft-deleted application
parameters:
- name: application
in: path
required: true
schema: { type: integer }
responses:
"200":
description: Application restored
content:
application/json:
schema:
type: object
properties:
data: { $ref: "#/components/schemas/Application" }
"403": { $ref: "#/components/responses/Forbidden" }
/v1/media:
post:
tags: [Media]
@@ -3363,6 +3567,98 @@ components:
links: { $ref: "#/components/schemas/PaginationLinks" }
meta: { $ref: "#/components/schemas/PaginationMeta" }
Call:
type: object
properties:
id: { type: integer }
locale: { type: string }
title: { type: string, nullable: true }
slug: { type: string, nullable: true }
description: { type: string, nullable: true }
what_you_get: { type: string, nullable: true }
status: { type: string, enum: [open, filled, closed] }
hours_per_week: { type: integer, nullable: true }
duration_weeks: { type: integer, nullable: true }
seniority: { type: string, nullable: true, enum: [any, junior, mid, senior] }
opens_at: { type: string, format: date, nullable: true }
closes_at: { type: string, format: date, nullable: true }
project_id: { type: integer, nullable: true }
technology_ids: { type: array, items: { type: integer } }
applications_count: { type: integer }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
translations: { type: object, nullable: true, description: "Every language, with `?with=translations`." }
CallWrite:
type: object
required: [title, slug]
properties:
title: { $ref: "#/components/schemas/TranslatedField" }
slug:
allOf: [{ $ref: "#/components/schemas/TranslatedField" }]
description: Unique per language.
description: { $ref: "#/components/schemas/TranslatedField" }
what_you_get: { $ref: "#/components/schemas/TranslatedField" }
status: { type: string, enum: [open, filled, closed], default: open }
hours_per_week: { type: integer, nullable: true, minimum: 1, maximum: 40 }
duration_weeks: { type: integer, nullable: true, minimum: 1 }
seniority: { type: string, nullable: true, enum: [any, junior, mid, senior] }
opens_at: { type: string, format: date, nullable: true }
closes_at: { type: string, format: date, nullable: true }
project_id: { type: integer, nullable: true }
technology_ids: { type: array, items: { type: integer } }
CallCollection:
type: object
properties:
data:
type: array
items: { $ref: "#/components/schemas/Call" }
links: { $ref: "#/components/schemas/PaginationLinks" }
meta: { $ref: "#/components/schemas/PaginationMeta" }
Application:
type: object
properties:
id: { type: integer }
kind: { type: string, enum: [contribute, request] }
status: { type: string, enum: [new, contacted, accepted, declined, spam] }
call_id: { type: integer, nullable: true }
subject: { type: string, description: "The call's title, or a general enquiry." }
name: { type: string }
email: { type: string, format: email }
organisation: { type: string, nullable: true }
message: { type: string }
hours_per_week: { type: integer, nullable: true }
links: { type: object, additionalProperties: { type: string }, description: "The links the sender gave, keyed as they were sent." }
locale: { type: string, description: The language it was written in. }
notes: { type: string, nullable: true, description: Private to the collective. }
handled_by:
type: object
nullable: true
properties:
id: { type: integer }
name: { type: string }
handled_at: { type: string, format: date-time, nullable: true }
created_at: { type: string, format: date-time }
updated_at: { type: string, format: date-time }
deleted_at: { type: string, format: date-time, nullable: true }
ApplicationWrite:
type: object
properties:
status: { type: string, enum: [new, contacted, accepted, declined, spam] }
notes: { type: string, nullable: true, maxLength: 10000 }
ApplicationCollection:
type: object
properties:
data:
type: array
items: { $ref: "#/components/schemas/Application" }
links: { $ref: "#/components/schemas/PaginationLinks" }
meta: { $ref: "#/components/schemas/PaginationMeta" }
MediaFor:
type: string
enum: [pages, technologies, projects, members, clients, testimonials]