Dispensa de disciplinas
A análise de dispensa recebe os documentos acadêmicos de um aluno — histórico escolar, ementas das disciplinas cursadas na instituição de origem e o plano de ensino do curso de destino — e devolve, para cada disciplina do destino, se ela pode ser dispensada, por qual disciplina de origem (ou combinação delas), com score de similaridade, motivo de recusa e justificativa.
A análise é assíncrona: o POST devolve a análise criada e o resultado
chega depois, por consulta (GET) ou por webhook.
Rotas
| método e rota | o que faz |
|---|---|
POST /v1/api/credit-transfer-analyses | inicia uma análise avulsa, com os arquivos enviados na própria requisição |
GET /v1/api/credit-transfer-analyses | lista as análises da empresa, mais recentes primeiro |
GET /v1/api/credit-transfer-analyses/{creditTransferAnalysisId} | status e, quando concluída, o resultado |
GET /v1/api/credit-transfer-analyses/{creditTransferAnalysisId}/spreadsheet | URL da planilha (.xlsx) do resultado |
POST /v1/api/competencies/{competencyId}/participants/{participantId}/credit-transfer-analyses | inicia a análise de um participante de projeto, com os documentos que ele já enviou |
Todas exigem a x-api-key (ver Autenticação).
Antes do primeiro envio
A dispensa de disciplinas precisa estar habilitada para a sua empresa. Sem
isso, os dois POST respondem 403 com context: "FEATURE_NOT_ENABLED".
Peça a habilitação ao seu contato na Dynadok.
Há dois jeitos de usar:
- Avulsa — você envia os arquivos direto na requisição. Não precisa de projeto, competência nem participante. É o caminho mais curto para integrar.
- Por participante — os documentos já foram enviados pelo aluno (ou por você) nos slots de uma competência configurada para a dispensa. Ver Análise de um participante.
Os três papéis de documento
papel (role) | documento | quantos |
|---|---|---|
HISTORIC | histórico escolar da instituição de origem | 1 ou mais |
ORIGIN_SYLLABUS | ementas / planos de ensino das disciplinas cursadas na origem | 1 ou mais |
DESTINATION_SYLLABUS | plano de ensino (ou matriz) do curso de destino | exatamente 1 |
Os três papéis são obrigatórios em toda análise.
Iniciar uma análise avulsa
Requisição multipart/form-data:
| campo | obrigatório | conteúdo |
|---|---|---|
files | sim | os arquivos, PDF ou imagem; até 30 por análise e 20 MB por arquivo |
roles | sim | o papel de cada arquivo, na mesma ordem de files — repita o campo uma vez por arquivo, ou envie um único campo com um array JSON (["HISTORIC","ORIGIN_SYLLABUS","DESTINATION_SYLLABUS"]) |
parameters | não | objeto JSON com os parâmetros da análise (ver abaixo); o que for omitido usa o padrão |
externalId | não | seu identificador para esta análise (até 200 caracteres), filtrável na listagem |
E um header opcional:
| header | conteúdo |
|---|---|
Idempotency-Key | até 255 caracteres. Repetir a requisição com a mesma chave devolve a análise criada na primeira vez, sem criar outra nem reprocessar — inclusive quando as duas chegam ao mesmo tempo. Use em todo retry do seu lado. |
curl --request POST 'https://api.dynadok.com/v1/api/credit-transfer-analyses' \
--header 'x-api-key: 550e8400-e29b-41d4-a716-446655440000.SUA_CHAVE' \
--header 'Idempotency-Key: matricula-2026-0001' \
--form 'files=@"/caminho/historico.pdf"' \
--form 'roles="HISTORIC"' \
--form 'files=@"/caminho/ementas-origem.pdf"' \
--form 'roles="ORIGIN_SYLLABUS"' \
--form 'files=@"/caminho/matriz-destino.pdf"' \
--form 'roles="DESTINATION_SYLLABUS"' \
--form 'parameters="{\"minScore\":80,\"allowCombination\":true}"' \
--form 'externalId="matricula-2026-0001"'
A resposta traz a análise já criada, normalmente em PROCESSING, com
subjects: null. Guarde o _id para consultar depois.
Parâmetros
| parâmetro | padrão | faixa | efeito |
|---|---|---|---|
minScore | 75 | 1–100 | score mínimo de similaridade de conteúdo para aprovar a equivalência |
creditHoursTolerance | 60 | 0–100 ou null | a carga horária de origem (ou a soma, numa combinação) precisa ser pelo menos esse percentual da carga horária de destino. null desliga a regra de carga horária |
complexity | NORMAL | NORMAL | HIGH | modo de comparação usado pelo motor de análise |
allowCombination | false | booleano | permite dispensar uma disciplina de destino pela soma de várias disciplinas de origem |
minScoreToDisplay | 50 | 0–100 | equivalências recusadas com score abaixo disso não aparecem no resultado. Equivalência aprovada aparece sempre |
Os parâmetros efetivos de cada análise voltam em parameters na resposta.
Acompanhar a análise
Status
| status | significado |
|---|---|
PENDING_DOCUMENTS | só na análise por participante: algum documento ainda está em processamento; a análise começa sozinha quando ele terminar |
QUEUED | criada, aguardando envio ao motor de análise |
PROCESSING | em análise |
COMPLETED | concluída; subjects e summary preenchidos |
FAILED | não concluiu; o motivo está em failure |
Análise que fica mais de 3 horas em QUEUED/PROCESSING, ou mais de
24 horas em PENDING_DOCUMENTS, é encerrada como FAILED.
Prefira o webhook ao polling. Se fizer polling, use um intervalo de dezenas de segundos — a análise leva minutos, não segundos.
Consultar
curl 'https://api.dynadok.com/v1/api/credit-transfer-analyses/6500a1b2c3d4e5f600000010' \
--header 'x-api-key: 550e8400-e29b-41d4-a716-446655440000.SUA_CHAVE'
Exemplo de análise concluída (valores ilustrativos):
{
"code": 200,
"message": "OK",
"timestamp": 1761148800000,
"data": {
"_id": "6500a1b2c3d4e5f600000010",
"status": "COMPLETED",
"source": "API_STANDALONE",
"trigger": "API",
"externalId": "matricula-2026-0001",
"competencyParticipantId": null,
"destinationCompetencyDocumentId": null,
"parameters": {
"minScore": 80,
"creditHoursTolerance": 60,
"complexity": "NORMAL",
"allowCombination": true,
"minScoreToDisplay": 50
},
"summary": { "destinationSubjects": 2, "exempted": 1, "exemptedByCombination": 0 },
"failure": null,
"createdAt": "2026-10-22T15:00:00.000Z",
"updatedAt": "2026-10-22T15:06:10.000Z",
"startedAt": "2026-10-22T15:00:02.000Z",
"completedAt": "2026-10-22T15:06:10.000Z",
"outdatedAt": null,
"subjects": [
{
"name": "Cálculo I",
"period": 1,
"workloadHours": 80,
"mandatoryPractice": false,
"exempted": true,
"exemptedBy": "EQUIVALENCE",
"equivalences": [
{
"originSubject": {
"name": "Cálculo Diferencial e Integral I",
"period": 1,
"workloadHours": 72,
"institution": "Universidade de Origem",
"course": "Engenharia Civil"
},
"score": 92,
"approved": true,
"rejectionReason": null,
"justification": "Conteúdo programático equivalente: limites, derivadas e integrais."
}
],
"combination": null
},
{
"name": "Física Experimental",
"period": 2,
"workloadHours": 60,
"mandatoryPractice": true,
"exempted": false,
"exemptedBy": null,
"equivalences": [
{
"originSubject": {
"name": "Física Geral",
"period": 2,
"workloadHours": 30,
"institution": "Universidade de Origem",
"course": "Engenharia Civil"
},
"score": 81,
"approved": false,
"rejectionReason": "CREDIT_HOURS",
"justification": "Conteúdo compatível, mas carga horária insuficiente."
}
],
"combination": null
}
]
}
}
Como ler o resultado
summaryresume: quantas disciplinas de destino (destinationSubjects), quantas dispensadas (exempted) e quantas delas por combinação (exemptedByCombination).- Cada item de
subjectsé uma disciplina do destino.exempteddiz se ela foi dispensada;exemptedBydiz como:EQUIVALENCE(uma disciplina de origem equivale) ouCOMBINATION(várias somadas, só comallowCombination: true). equivalenceslista as disciplinas de origem comparadas, comscore(0–100),approved,justificatione, quando recusada,rejectionReason.combination, quando houve tentativa de combinação, trazoriginSubjects,score,approvederejectionReasondo conjunto.mandatoryPractice: trueindica disciplina de prática obrigatória no destino.- Campos que o motor não conseguiu extrair do documento vêm
null(nome, período, carga horária, instituição, curso).
rejectionReason | significado |
|---|---|
CONTENT | conteúdo insuficiente: score abaixo de minScore |
CREDIT_HOURS | carga horária de origem abaixo de creditHoursTolerance |
ORIGIN_ALREADY_USED | a disciplina de origem já foi usada para dispensar outra |
REUSE_LIMIT | atingido o limite de reaproveitamento da disciplina de origem |
Falha
Em FAILED, failure traz code e uma message em português, pronta para
exibir:
failure.code | significado |
|---|---|
UNREADABLE_FILE | algum arquivo não pôde ser lido |
MULTIPLE_DOCUMENTS_IN_FILE | um arquivo contém mais de um documento |
PROCESSING_ERROR | falha no processamento ou prazo esgotado — tente de novo |
Planilha
curl 'https://api.dynadok.com/v1/api/credit-transfer-analyses/6500a1b2c3d4e5f600000010/spreadsheet' \
--header 'x-api-key: 550e8400-e29b-41d4-a716-446655440000.SUA_CHAVE'
{
"code": 200,
"message": "OK",
"timestamp": 1761148800000,
"data": {
"url": "https://...",
"expiresAt": "2026-10-29T15:10:00.000Z"
}
}
A planilha é gerada na primeira chamada e reaproveitada nas seguintes. A url
é assinada e vale 7 dias (expiresAt); depois disso, chame a rota de novo
para obter outra. Antes de a análise concluir, a rota responde 409 com
context: "ANALYSIS_NOT_COMPLETED".
Listar análises
GET /v1/api/credit-transfer-analyses pagina com page e perPage (máx.
100), mais recentes primeiro, com filtros opcionais externalId, status e
competencyParticipantId. Cada item traz o mesmo objeto da consulta sem
subjects — use summary para a visão geral e consulte por id para o
detalhe. O formato da paginação está em Envelope e erros.
curl 'https://api.dynadok.com/v1/api/credit-transfer-analyses?externalId=matricula-2026-0001' \
--header 'x-api-key: 550e8400-e29b-41d4-a716-446655440000.SUA_CHAVE'
Webhook
Ao terminar, a análise dispara um evento para os webhooks da empresa:
| evento | quando |
|---|---|
CREDIT_TRANSFER_ANALYSIS_COMPLETED | análise concluída (status: COMPLETED) |
CREDIT_TRANSFER_ANALYSIS_FAILED | análise falhou (status: FAILED) |
data é o mesmo objeto de GET /v1/api/credit-transfer-analyses/{id}:
{
"event": "CREDIT_TRANSFER_ANALYSIS_COMPLETED",
"data": { "_id": "6500a1b2c3d4e5f600000010", "status": "COMPLETED", "externalId": "matricula-2026-0001", "subjects": [] }
}
A análise avulsa não pertence a projeto nenhum. Um webhook restrito a projetos nunca recebe esses eventos dela, sem erro nem aviso. Configure um webhook sem restrição de projeto. A análise por participante chega tanto no webhook da empresa toda quanto no restrito ao projeto do participante.
Leia Webhooks antes de implementar o endpoint: uma resposta
4xx/5xx do seu lado não gera reenvio.
Análise de um participante
Quando o aluno é um participante de projeto, a competência pode ser configurada para a dispensa: cada slot de documento recebe um papel (histórico, plano de ensino de origem ou de destino), e os parâmetros da análise ficam no slot do plano de ensino de destino. Essa configuração é feita na plataforma.
Com o slot de destino em modo automático (o padrão), a análise começa sozinha quando o plano de ensino de destino termina de processar — não é preciso chamar a API. O gatilho é só o documento de destino: se nesse momento ainda faltar histórico ou ementa de origem, a análise não começa e nada é avisado. Envie o plano de destino por último ou, se ele chegou antes dos outros, inicie pela rota abaixo — que também serve para o modo manual e para refazer a análise:
curl --request POST 'https://api.dynadok.com/v1/api/competencies/6500a1b2c3d4e5f600000001/participants/6500a1b2c3d4e5f600000002/credit-transfer-analyses' \
--header 'x-api-key: 550e8400-e29b-41d4-a716-446655440000.SUA_CHAVE' \
--header 'Content-Type: application/json' \
--data '{}'
O corpo aceita competencyDocumentId (opcional): o slot do plano de ensino de
destino a usar. Só é obrigatório quando a competência tem mais de um slot de
destino.
- Se algum documento ainda está em processamento, a análise fica em
PENDING_DOCUMENTSe começa quando ele terminar. - Só existe uma análise em andamento por participante e slot de destino; pedir
outra responde
409(ANALYSIS_ALREADY_RUNNING, com o id da análise emextraData.creditTransferAnalysisId). - Se o participante reenviar um documento depois da análise, ela ganha
outdatedAtpreenchido. Reenvio do plano de destino em modo automático dispara uma análise nova (se houver uma em andamento, a nova começa quando ela terminar). Reenvio de histórico ou ementa de origem só marca a análise como desatualizada — refaça pela rota acima.
Para filtrar as análises de um participante, use
GET /v1/api/credit-transfer-analyses?competencyParticipantId=....
Erros típicos
O envelope de erro está em Envelope e erros; o
context identifica o caso.
| status | context | quando |
|---|---|---|
403 | FEATURE_NOT_ENABLED | dispensa não habilitada para a empresa |
400 | ROLES_FILES_MISMATCH | quantidade de roles diferente da de files |
400 | TOO_MANY_FILES | mais de 30 arquivos |
400 | MISSING_REQUIRED_DOCUMENTS | falta algum dos três papéis; extraData.missingRoles lista quais |
400 | MULTIPLE_DESTINATION_SYLLABUS | mais de um DESTINATION_SYLLABUS |
400 | UNSUPPORTED_FILE_TYPE | arquivo que não é PDF nem imagem |
400 | UNREADABLE_FILE | arquivo que não pôde ser lido; extraData.fileName diz qual |
400 | INVALID_MULTIPART_FIELD | roles ou parameters em formato inválido; extraData.field diz qual |
400 | INVALID_DESTINATION_SLOT / DESTINATION_SLOT_REQUIRED | por participante: slot de destino inválido ou não informado quando há mais de um |
404 | — | análise, competência ou participante inexistente |
409 | ANALYSIS_ALREADY_RUNNING | por participante: já há análise em andamento |
409 | ANALYSIS_NOT_COMPLETED | planilha pedida antes de a análise concluir |