Aller au contenu

Cria um space

POST/api/spaces

Auth
Jeton requis
Qui peut l’appeler:
owner
admin
Clé d’API:
community:write
X-CommunityId
X-CommunityId Envoyez le X-CommunityId de la communauté où l’opération a lieu.
Les descriptions des endpoints viennent directement de la spécification de l’API et sont en portugais pour l’instant. L’interface autour est traduite.

Sujeito a verificação de papel (RBAC): owner e admin. A comunidade é a do `X-CommunityId`.

**Extensões:** um módulo das categorias `people` ou `coworking` que o plano da comunidade não libera (`locked: true` em `GET /api/spaces/modules`) responde 403 (`errors[].param = "module"`).

**Reservas:** só um espaço `bookings` por comunidade (409 ao criar ou mudar outro para Reservas). Em `bookings` e `scheduling`, chave desconhecida na raiz de `moduleConfig` dá 400 por campo (`errors[].param = "moduleConfig.<chave>"`); só `moduleConfig.bookings` / `moduleConfig.scheduling` valem.

**"Um curso só":** para `module: courses`, `moduleConfig: { mode: "single" }` e o objeto opcional `course: { title, level, description }` criam o espaço e o curso numa só transação (o curso em rascunho). Sem `course`, o espaço nasce sem curso. Ver `moduleConfig` e `course`.

En-têtes

NomTypeDescription
X-CommunityIdfacultatifstring (uuid)ID da comunidade em que a operação acontece. Obrigatório na maioria dos endpoints com escopo de comunidade.

Corps de la requête application/json

NomTypeDescription
sectionIdobligatoirestring (uuid)Valid section ID is required
titleobligatoirestringTitle is required · max 255
descriptionfacultatifstringDescription must be a string
slugfacultatifstringLetras minúsculas, números e hífen. Não pode começar com _ (rotas internas do app ficam em /_/): 400 com param = slug. Gerado do título quando ausente, nunca com _. · max 255
iconfacultatifstringIcon must be 100 characters or less · max 100
orderfacultatifintegerOrder must be a non-negative integer
moduleobligatoirestringInvalid module type
externalUrlfacultatifstring (uri)Invalid URL format
visibilityfacultatifpublic | members | plan | privateNunca mais aberta que a da seção que contém o space, na ordem `public` < `members` < `plan` < `private`. Mais aberta devolve 400.
accessfacultatifobjectQuem entra quando `visibility` é `private`. Opcional e **aditivo**: ausente não mexe em nada. Cada lista (`groupIds`, `productIds`, `subscriptionGroupIds`, `badgeIds`) e o nível (`minLevelId`/`minLevel`) só mudam quando vêm no pedido: **ausente (ou `null`) mantém** o que está lá, a lista enviada **substitui** a daquele tipo e `[]` tira todos. Mandar só o nível não mexe em grupos nem produtos. As listas são **união** — satisfazer qualquer uma basta. Um id de outra comunidade, ou uma lista que não é array, devolve 400 com `errors`.
access.groupIdsfacultatifstring (uuid)[]
access.productIdsfacultatifstring (uuid)[]
access.subscriptionGroupIdsfacultatifstring (uuid)[]
access.badgeIdsfacultatifstring (uuid)[]Badges da comunidade (não apagados); quem tem um deles (não revogado) entra. Como as outras listas, **ausente (ou `null`) mantém** os badges que já estão lá; `[]` tira todos. Badge de outra comunidade, apagado ou id inválido devolve 400 com `errors`.
access.minLevelIdfacultatifstring (uuid)"A partir do nível": quem está nesse nível do Engajamento ou acima (o nível gravado, o mesmo do perfil e do ranking) entra. Um por espaço ou seção. Ausente mantém; `null` tira. Nível de outra comunidade ou id inválido devolve 400 com `errors`. Com a gamificação desligada, o nível não abre nada.
access.minLevelfacultatifintegerO mesmo nível pelo número (1 é o primeiro), para a escada ainda nos níveis padrão, que não têm id antes do primeiro uso; vira `minLevelId`. Número fora da escada → 400. · ≥ 1
moduleConfigfacultatifobjectConfiguração específica do módulo, preenchida no wizard. A forma depende do módulo — `call4papers` guarda o modo do space e a primeira chamada. Enviar `null` limpa. **Presença (`attendance`) e Encomendas (`parcels`): `retentionMonths`.** Dentro da chave do módulo (`moduleConfig.attendance.retentionMonths`, `moduleConfig.parcels.retentionMonths`), um inteiro de 6 a 60, padrão 12: por quantos meses os dados de visitantes (contados da chegada ou do dia esperado) e de encomendas fechadas (contados de quando foram recebidas e fechadas) ficam guardados antes de a rotina diária de retenção apagá-los. Fora da faixa: 400 com `errors[].param = "moduleConfig.<módulo>.retentionMonths"`. Um prazo **menor** que o em vigor só passa a valer 7 dias depois (até lá vale o anterior; a configuração lida traz `retentionMonthsPrevious` e `retentionMonthsEffectiveAt` enquanto isso), um maior vale na hora, e a troca entra no log de atividades da equipe (`space.retention_changed`, com o antes e o depois). Na edição o prazo nunca se perde: `moduleConfig: null`, sem a chave do módulo ou sem `retentionMonths` mantêm o salvo. Os dois campos de data são só do servidor (ignorados se enviados). Antes de salvar, `GET /api/spaces/{id}/retention-preview?months=N` diz quantos registros sairiam. **Espaço de Suporte (`support`): chave `support`.** `allowUrgentFlag` (boolean, padrão `true`), `maxOpenPerMember` (0 a 1000, padrão 10; 0 = sem teto), `locationHint` (texto até 200), `responders` e `sla`. `responders` diz **quem responde** os chamados: `{ tags: [nome], groupIds: [uuid], memberIds: [uuid], byCategory: { INTERNET: { tags, groupIds, memberIds } } }`. Tags valem pelo **nome** (sem diferenciar maiúsculas; renomear a tag atualiza a configuração), grupos contam só os membros diretos e as pessoas precisam ser da equipe (owner, admin, moderador ou financeiro); o resultado é cruzado com os papéis da equipe, então um membro comum nunca responde. `byCategory` sobrescreve o space para aquela categoria. Vazio = toda a equipe responde; seleção configurada que não acha ninguém = só owner e admin. `sla` guarda `{ enabled, categories: { FACILITIES: { firstResponse: { value, unit }, resolution: { value, unit } } } }` com `unit` `hours` ou `days` mais `businessHours` (`{ days: [1,2,3,4,5], start: "09:00", end: "18:00" }`, padrão seg a sex 09-18); o prazo sai do horário de atendimento no fuso da comunidade. `defaultAssigneeId` (uuid ou `null`) é quem recebe os chamados novos: precisa ser da equipe e responder ao menos uma categoria, senão 400. Campo inválido: 400, um item em `errors` por campo (`moduleConfig.support.…`). O residente nunca recebe `responders` (nem em `GET /api/spaces`). **Espaço de Cursos (`courses`): chave `mode`.** `"multi"` (lista de cursos, o padrão quando a chave não existe) ou `"single"` ("Um curso só": o espaço é um curso). Outro valor, 400 com `errors[0].param = "moduleConfig.mode"`; a chave num espaço de outro módulo, 400. Na edição, num espaço de Cursos a gravação é **por chave** (mescla com o que já existe) e `mode` só muda quando a requisição o traz: gravar outra chave nunca o apaga, e `null` limpa as outras chaves mas mantém o `mode`. Trocar para `"single"` com 0 ou 1 curso passa; com 2 ou mais, 409 dizendo quantos há (rascunhos e arquivados contam; nada é apagado). Trocar para `"multi"` sempre passa, com matrículas e progresso intactos. A conferência roda sob trava na linha do espaço, contra criação de curso em paralelo.
canCreatefacultatifanyone | staff | adminsQuem cria conteúdo no space (post, status, evento, curso, imagem de galeria). `anyone`: quem a rota já aceita; `staff`: owner, admin, moderator e finance; `admins`: owner e admin. Opcional: na criação o padrão é `anyone`; na edição, ausente não mexe. Comentar e reagir não dependem disso.
feedScopefacultatifspace | sectionSó no módulo `feed` (em outro módulo, 400 com `errors[0].param = "feedScope"`). O que o feed mostra em `GET /api/feed?spaceId=`: `space`, só os posts deste espaço; `section`, os itens de todos os espaços da seção. Ausente na criação, o Feed nasce `section` se é o único Feed da seção e `space` se a seção já tem outro. Coluna própria: mudar a opção não mexe no `moduleConfig`. Na edição, ausente não mexe.
feedWidgetsfacultatifobjectSó no módulo `feed` (em outro módulo, 400 com `errors[0].param = "feedWidgets"`). Os widgets da coluna lateral do Feed (`GET /api/feed/sidebar`), cada um `true` ou `false`. Merge parcial: as chaves enviadas substituem as gravadas e as outras ficam como estão; `null` volta ao padrão. Sem nada gravado: `events` e `trending` ligados, `newMembers` e `leaderboard` desligados. Coluna própria: não mexe no `moduleConfig`. Só owner e admin.
feedWidgets.eventsfacultatifboolean
feedWidgets.trendingfacultatifboolean
feedWidgets.newMembersfacultatifboolean
feedWidgets.leaderboardfacultatifboolean
layoutfacultatiffeed | cards | list | compact | grid | showcase | calendar"Exibição": como o espaço lista os itens. Só os valores de `layouts.options` do módulo em `GET /api/spaces/modules` (Conteúdo `feed`, `cards`, `list`, `compact`; Eventos `cards`, `list`, `compact`, `calendar`; Cursos `cards`, `list`, `showcase` (Vitrine: grade de pôsteres); Downloads `cards`, `list`, `compact`; Classificados `cards`, `list`; Galeria `grid`, `feed`). Fora disso (`showcase` fora de Cursos, `calendar` fora de Eventos), ou em módulo sem a opção: 400 com `errors[0].param = "layout"`. Ausente ou `null`: o padrão do módulo (`layouts.default`), e a coluna fica nula. Coluna própria: não mexe no `moduleConfig`.
lockedDisplayfacultatifinherit | hide | show"Para quem não tem acesso": `inherit` (igual à seção, o padrão), `hide` (some) ou `show` (aparece com cadeado). Quando a seção barrou a pessoa, `inherit` segue a seção; quando a seção deixou passar e quem barra é o space, `inherit` mostra com cadeado salvo se a seção está em `hide`. Com a seção em `section`, os spaces nunca aparecem. Área só administração nunca vira cadeado. Na edição, ausente não mexe.
coursefacultatifobjectSó para `module: courses` com `moduleConfig.mode = "single"` ("Um curso só"): cria o espaço e o curso **juntos, numa única transação** (se o curso falhar, nada é criado). O curso nasce em **rascunho**, com o slug gerado do título. Em qualquer outro caso, 400 com `errors[0].param = "course"`. A resposta traz o curso criado em `data.course`, com `data.course.certificate` (a configuração do certificado).
course.titleobligatoirestringmax 255
course.levelfacultatifbeginner | intermediate | advanced
course.descriptionfacultatifstring
course.certificatefacultatifobjectCertificado na conclusão, o mesmo bloco de `POST /api/courses`: `{ enabled, templateId?, text? }`. Ausente, o curso nasce desligado. Erros em `errors[].param = certificate.*`; se algo falhar, nem o espaço nem o curso nascem.

Réponses

StatutDescription
201Space criado (e o curso, em `data.course`, quando veio `course`).
400Campo inválido; `moduleConfig.mode` inválido ou fora de um espaço de Cursos; `course` fora de "Um curso só".
401Token ausente, inválido ou expirado; token de outra comunidade (o `X-CommunityId` ou o `communityId` do corpo não é o do token); token antigo ou de uma sessão encerrada (troca de senha, convite aceito). Nesses casos a mensagem pede para entrar de novo (`auth.signInAgain`).
403Autenticado, mas sem permissão para esta operação.
500Erro interno do servidor.

Exemple curl

curl -X POST "https://api.memberfy.net/api/spaces" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-CommunityId: $COMMUNITY_ID" \
  -H "Content-Type: application/json" \
  -d '{"sectionId":"00000000-0000-0000-0000-000000000000","title":"string","module":"string"}'