Moraviq Voice para desenvolvedoresAPI v2

API v2

REST em JSON sob /v2, mais o WebSocket /v2/signaling que os SDKs usam. Tudo é do parceiro da credencial: o Voice nunca aceita o parceiro vindo do corpo. Chamada inexistente, de outro parceiro, de outro site ou sem participação dá o mesmo 404 call_not_found. Referência completa: OpenAPI 3.1.

Modelo

ConceitoNo Voice
Condomíniosite: ext_id seu, cadastrado com PUT /v2/sites/{site}
Guarita, portariaposto (station) do site, com rótulo de até 32 caracteres
Morador, porteiroext_id seu no sub do token de aparelho; o Voice não guarda nome
Unidade, grupotarget da chamada: unit, group ou users

Rotas

RotaQuemO que faz
PUT /v2/sites/{site}servidor sites:writecria ou atualiza enabled, max_concurrent (1 a 500), ring_timeout_s (15 a 60, padrão 30), retention_days (30 a 365), busy_policy, authorization (prior ou callback)
DELETE /v2/sites/{site}servidor sites:writedesliga; chamadas em curso terminam com revoked
PUT /v2/sites/{site}/stations/{station}servidor sites:write{"label"}
POST /v2/callsservidor calls:create ou aparelho call:place (site callback)cria; Idempotency-Key obrigatório
GET /v2/calls/{call_id}servidor calls:read ou participantea chamada, com os campos do seu papel
GET /v2/callsservidor calls:read ou participante?site=&since=&cursor=&limit= (até 100); {"items", "next_cursor"}
POST /v2/calls/{call_id}/accept, /rejectconvidado{"device_id"}; o primeiro aceite vence: 409 taken_elsewhere
POST /v2/calls/{call_id}/ring-ackconvidado{"device_id", "result"}: o push tocou de verdade
POST /v2/calls/{call_id}/cancelservidor calls:end ou origemsó antes do aceite
POST /v2/calls/{call_id}/hangupservidor calls:end, origem ou quem atendeuidempotente
POST /v2/calls/{call_id}/dispositionservidor calls:end ou quem atendeu{"code"}: allowed, denied, no_response. Informação: nunca abre portão
POST /v2/calls/{call_id}/device-tokenaparelho convidado, com provatoken curto da chamada (autenticação)
POST /v2/devicesaparelho call:receiveregistra o aparelho (installation_id, platform, push_type, push_token); devolve device_secret; Idempotency-Key obrigatório
DELETE /v2/devices/{device_id}dono do aparelhorevoga o aparelho e a credencial
DELETE /v2/users/{user}/devicesservidor devices:revokerevoga tudo da pessoa e encerra as chamadas dela
POST /v2/ice-credentialsparticipanteSTUN e TURN temporários da chamada
POST /v2/ws-ticketparticipanteticket de uso único (30 s) para abrir o /v2/signaling

Criar a chamada

Dois modos, escolhidos por site (authorization) ou pelo padrão da conta:

ModoQuem criaQuem decide quem toca
prior (padrão)o seu backendo seu backend, em callees (obrigatório, até 20)
callbacko aparelho (call:place)o Voice pergunta ao seu authorize_url, assinado, em até 3 s
POST /v2/calls
Authorization: Bearer <asserção com calls:create>
Idempotency-Key: pedido-123

{
  "site": "cond_jardins",
  "target": {"kind": "unit", "ref": "A-304"},
  "callees": ["res_77", "res_78"],
  "caller": {"user": "port_12", "station": "guarita_1"},
  "context": {"reason": "delivery", "reason_label": "Mercado"},
  "labels": {"target": "Apto 304"},
  "metadata": {"pedido": "ped_123"},
  "ring_timeout_s": 30
}

O que pode sair

Na ordem em que o Voice confere: conta suspensa (403 partner_disabled); site desligado (404 site_not_found); alvo ocupado com one_per_target (busy/target_busy); teto do site ou da conta (failed/site_limit ou partner_limit); callback negado (403 not_allowed); ninguém alcançável (failed/no_devices); grupo com todos ocupados (busy/attendants_busy); senão ringing. Antes de tudo, a cota por posto: 30 chamadas em 10 minutos (429 rate_limited, detail: station_quota).

A chamada (CallView)

id, status, end_reason, created_at, answered_at, ended_at, ring_expires_at, role, site, target, sequence, disposition, context, e por papel:

Camposervidororigemconvidado e quem atendeu
devices_ringingsimsim, menos em groupnão
caller.user, caller.stationsimsimnão
answered_bydepois do aceitedepois do aceitenão
labelsnãosimnão
metadatasimnãonão
caller.station_labelnãonãosim
my_invitation_statusnãonãosim

Estados

created → ringing → connecting (aceita) → active (áudio conectado). Terminais: completed, missed, cancelled, rejected, failed, busy. end_reason: normal, no_answer, origin_cancelled, origin_gone, all_rejected, no_devices, quiet_hours, site_limit, partner_limit, target_busy, attendants_busy, ice_timeout, media_lost, signaling_lost, max_duration, revoked. Prazos: toque até o ring_timeout_s do site, conexão de mídia em 15 s, duração máxima de 1 h.

Idempotência

Idempotency-Key (8 a 64 de [A-Za-z0-9_.:-]) é obrigatório em POST /v2/calls e POST /v2/devices; sem ele, 400 bad_request. Guardado por 24 h, ligado a quem pediu, à rota e ao corpo: o mesmo pedido devolve a resposta guardada com 200; corpo diferente com a mesma chave, 422 idempotency_conflict; o primeiro ainda em curso, 409 idempotency_in_progress. Use o id do pedido do seu sistema.

WebSocket /v2/signaling

Os SDKs fazem isto por você; está aqui para quem escreve o próprio cliente.

A suíte de conformidade (sdk/conformidade) descreve cada um desses fluxos frame a frame, e todo SDK oficial roda os mesmos cenários.