# API Darkvi — Referência completa
Base URL: https://darkvi.com/api
Autenticação: Bearer Token (header Authorization)

Cole este texto em qualquer IA para ter contexto completo da API e gerar código de integração.

---

### GET https://darkvi.com/api/v1/auth/validate
Verifica se uma chave de API está válida e associada a um usuário existente.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```
Envie a chave que deseja validar no cabeçalho Authorization.

**Respostas:**
- **200 OK**: A chave de API é válida.
```json
{
  "success": true,
  "valid": true
}
```
- **401 Unauthorized**: Chave ausente, malformada, inexistente ou de um usuário que não existe mais. Todos os casos têm a mesma resposta.
```json
{
  "error": true,
  "url": "https://darkvi.com/api/v1/auth/validate",
  "statusCode": 401,
  "statusMessage": "Token inválido.",
  "message": "Token inválido."
}
```

**Notas:**
- O endpoint não retorna a chave recebida nem dados pessoais do usuário.
- Não há códigos de erro separados: qualquer falha de autenticação responde 401 com statusMessage "Token inválido.". Confira o status HTTP.
- Se a requisição levar o cookie de sessão do Darkvi (por exemplo, no navegador de quem está logado em darkvi.com), a sessão vale como autenticação e a resposta é valid: true mesmo sem chave. Para validar uma chave, chame a partir do seu servidor ou sem cookies.

---

### POST https://darkvi.com/api/tts
Cria um texto para conversão em áudio e inicia o processamento.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```
O token deve estar associado a um usuário ativo.

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `text` | string | body | Sim | Texto a ser convertido em áudio. Limite por áudio conforme o plano: 80.000 caracteres (Starter e LITE) ou 120.000 (PRO e pay-as-you-go). Ex: `Olá, este é um teste...` |
| `voice` | string (idApi) | body | Sim | Identificador da voz: o campo idApi de cada item em GET /api/tts/voices. Deve existir e estar ativa. Ex: `3cfdsf3b-f69e-4533-8302-7d63f7cb5672` |
| `title` | string | body | Não | Título opcional para identificar o áudio. Ex: `Meu primeiro áudio` |

**Exemplo de requisição (body JSON):**
```json
{
  "text": "Olá, este é um teste de conversão de texto para fala.",
  "voice": "3cfdsf3b-f69e-4533-8302-7d63f7cb5672",
  "title": "Meu primeiro áudio"
}
```

**Respostas:**
- **201 Created**: Texto aceito e encaminhado para processamento.
```json
{
  "ok": true,
  "message": "Texto criado e encaminhado para processamento.",
  "data": {
    "created": {
      "id": "uuid",
      "status": "PENDING"
    }
  }
}
```

---

### GET https://darkvi.com/api/tts/audios/:id?name=Opcional
Retorna o MP3 gerado pelo TTS.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `id` | string (uuid) | path | Sim | ID do áudio/textspeech. Ex: `4cb014d7-0061-42e4-8c09` |
| `name` | string | query | Não | Nome opcional do arquivo no Content-Disposition. Ex: `meu-audio` |

**Respostas:**
- **200 OK (audio/mpeg)**: Binário MP3.
- **404 Not Found**: Áudio não encontrado.
```json
{
  "ok": false,
  "error": true,
  "code": "AUDIO_NOT_FOUND",
  "message": "Áudio não encontrado."
}
```

---

### GET https://darkvi.com/api/tts/srt/:id
Gera o arquivo .srt (legenda) do áudio solicitado a partir dos dados de transcrição salvos no banco.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```
Obrigatório. Use a API key gerada em darkvi.com/settings.

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `id` | string (uuid) | path | Sim | UUID do áudio (mesmo ID retornado ao criar o TTS em POST /api/tts ou listado em GET /api/tts). O áudio precisa estar com status DONE e pertencer ao usuário autenticado. Ex: `17beee29-af06-4425-a7c4-2b86c2ecdf2a` |
| `titulo` | string | query | Não | Título opcional usado para definir o nome do arquivo no download (Content-Disposition). Ex: `meu-video-01` |

**Respostas:**
- **200 OK (application/x-subrip)**: Conteúdo SRT em texto (download).
```json
1
00:00:00,000 --> 00:00:02,000
Olá, este é um exemplo.
```
- **400 Bad Request**: ID não informado ou inválido.
```json
{
  "ok": false,
  "error": true,
  "code": "INVALID_ID"
}
```
- **403 Forbidden**: O áudio não pertence ao usuário autenticado.
```json
{
  "ok": false,
  "error": true,
  "code": "FORBIDDEN"
}
```
- **404 Not Found**: Áudio não encontrado ou sem dados de legenda para gerar o SRT.
```json
{
  "ok": false,
  "error": true,
  "code": "SRT_EMPTY"
}
```
- **500 Internal Server Error**: Falha ao gerar o SRT a partir dos dados de transcrição.
```json
{
  "ok": false,
  "error": true,
  "code": "SRT_GENERATION_ERROR"
}
```

**Notas:**
- O :id é o UUID do áudio (ex.: 17beee29-af06-4425-a7c4-2b86c2ecdf2a), retornado no POST /api/tts ao criar o áudio.
- O áudio precisa estar com status DONE e ter transcrição salva. Áudios PENDING/PROCESSING ainda não têm SRT.
- O nome do arquivo será '<titulo>.srt' se 'titulo' for enviado, ou '<titulo-do-audio>.srt' caso exista; senão '<id>.srt'. Caracteres não-ASCII são removidos do filename ASCII e preservados via filename*=UTF-8 (RFC 5987).

---

### GET https://darkvi.com/api/tts/voices
Retorna a lista de vozes ativas disponíveis para TTS.

**Respostas:**
- **200 OK**: Array com as vozes ativas, em ordem alfabética. Use o idApi no campo voice de POST /api/tts.
```json
[
  {
    "idApi": "3f1ccc26-68a7-4617-b33b-0a5d9da20484",
    "name": "Tiago",
    "novidade": false,
    "language": "pt",
    "accent": "",
    "OtherLanguage": [
      "pt"
    ],
    "age": "young",
    "Urlpreview": "https://bigcloud.pro/darkvi_voice_preview/3f1ccc26-68a7-4617-b33b-0a5d9da20484.mp3"
  },
  {
    "idApi": "d028299c-65b1-434e-84d7-b0e16a193783",
    "name": "Valentino",
    "novidade": false,
    "language": null,
    "accent": null,
    "OtherLanguage": [],
    "age": null,
    "Urlpreview": "https://bigcloud.pro/darkvi_voice_preview/9c1f4ef2-6951-4a77-8452-921ed321a3f4.mp3"
  }
]
```
- **500 Internal Server Error**: Falha inesperada ao consultar as vozes.
```json
{
  "ok": false,
  "error": true,
  "code": "INTERNAL_ERROR",
  "message": "Erro interno inesperado."
}
```

**Notas:**
- Não exige autenticação: a lista de vozes é pública e responde sem chave de API.
- language é o idioma principal da voz (código ISO, ex.: pt, en, es) e OtherLanguage lista os outros idiomas que ela fala; vozes multilíngues podem vir com language null.
- Urlpreview é um MP3 curto de prévia, público, para ouvir a voz antes de gerar.

---

### POST https://darkvi.com/api/v1/srt
Envia um áudio externo e inicia a geração assíncrona da legenda SRT. Use o ID retornado para consultar o status.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```
Token gerado em darkvi.com/settings.

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `file` | file (multipart/form-data) | body | Sim | Áudio externo em MP3, WAV, M4A, AAC, OGG ou FLAC. Tamanho máximo: 50 MB. Ex: `audio.mp3` |

**Exemplo de requisição (body JSON):**
```json
"multipart/form-data com campo file"
```

**Respostas:**
- **201 Created**: Áudio aceito e encaminhado para transcrição.
```json
{
  "success": true,
  "id": "24e3cf5d12864b05ad0135f2caf746dc",
  "status": "PENDING",
  "filename": "entrevista.mp3",
  "statusUrl": "/api/v1/srt/24e3cf5d12864b05ad0135f2caf746dc",
  "downloadUrl": "/api/v1/srt/24e3cf5d12864b05ad0135f2caf746dc/download",
  "usage": {
    "used": 1,
    "limit": 10,
    "remaining": 9,
    "resetAt": "2026-09-27T03:00:00.000Z"
  }
}
```
- **413 Payload Too Large**: O arquivo ultrapassa 50 MB.
```json
{
  "statusCode": 413,
  "statusMessage": "O áudio deve ter no máximo 50 MB."
}
```
- **415 Unsupported Media Type**: A extensão do arquivo não é suportada.
```json
{
  "statusCode": 415,
  "statusMessage": "Formato não suportado. Envie MP3, WAV, M4A, AAC, OGG ou FLAC."
}
```
- **429 Too Many Requests**: O usuário já iniciou 10 conversões externas no dia.
```json
{
  "statusCode": 429,
  "statusMessage": "Limite diário de 10 SRTs para áudios externos atingido. Tente novamente amanhã."
}
```

**Notas:**
- Este limite vale apenas para áudios externos e é compartilhado com a página /srt.
- Legendas de áudios criados pelo TTS continuam livres e usam GET /api/tts/srt/:id.
- Faça polling a cada 2–4 segundos em GET /api/v1/srt/:id até status=DONE.

---

### GET https://darkvi.com/api/v1/srt/:id
Consulta o estado de uma conversão de áudio externo pertencente ao usuário autenticado.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `id` | string | path | Sim | ID retornado por POST /api/v1/srt. Ex: `24e3cf5d12864b05ad0135f2caf746dc` |

**Respostas:**
- **200 OK**: Estado atual da tarefa.
```json
{
  "success": true,
  "id": "24e3cf5d12864b05ad0135f2caf746dc",
  "filename": "entrevista.mp3",
  "status": "DONE",
  "error": null,
  "createdAt": "2026-09-26T18:00:00.000Z",
  "downloadUrl": "/api/v1/srt/24e3cf5d12864b05ad0135f2caf746dc/download"
}
```
- **404 Not Found**: Tarefa inexistente ou pertencente a outro usuário.
```json
{
  "statusCode": 404,
  "statusMessage": "Tarefa SRT não encontrada."
}
```

**Notas:**
- status pode ser PENDING, PROCESSING, DONE ou ERROR.
- downloadUrl fica null enquanto o arquivo ainda não estiver pronto.

---

### GET https://darkvi.com/api/v1/srt/:id/download
Baixa o arquivo SRT depois que a tarefa atingir status DONE.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `id` | string | path | Sim | ID retornado por POST /api/v1/srt. Ex: `24e3cf5d12864b05ad0135f2caf746dc` |

**Respostas:**
- **200 OK (application/x-subrip)**: Conteúdo do arquivo SRT.
```json
1
00:00:00,000 --> 00:00:02,000
Primeira legenda.
```
- **409 Conflict**: A tarefa ainda não terminou.
```json
{
  "statusCode": 409,
  "statusMessage": "O SRT ainda está sendo gerado."
}
```
- **404 Not Found**: Tarefa inexistente ou pertencente a outro usuário.
```json
{
  "statusCode": 404,
  "statusMessage": "Tarefa SRT não encontrada."
}
```

**Notas:**
- O nome baixado é derivado do nome original do áudio e termina em .srt.

---

### POST https://darkvi.com/api/v1/images
Cria um prompt de geração de imagem e inicia o processamento assíncrono. A geração é feita por um worker externo; use GET /api/v1/images/:id para acompanhar o status e obter a URL assinada quando status=DONE.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```
Token gerado em darkvi.com/settings. O token deve pertencer a um usuário ativo.

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `prompt` | string | body | Sim | Descrição da imagem a ser gerada. Máximo: 1000 caracteres. Ex: `Um dragão voando sobre montanhas nevadas ao pôr do sol, estilo fotorrealista` |
| `aspect` | string | body | Não | Proporção da imagem. Valores aceitos: "16:9" (paisagem) ou "9:16" (retrato/shorts). Omitir para proporção padrão. Ex: `16:9` |
| `referencePath` | string | body | Não | Key da imagem de referência (obtida em POST /api/v1/images/reference). Requer plano pago ou ADMIN. Formato esperado: reference_image/<uuid>.webp. Ex: `reference_image/550e8400-e29b-41d4-a716-446655440000.webp` |

**Exemplo de requisição (body JSON):**
```json
{
  "prompt": "Um dragão voando sobre montanhas nevadas ao pôr do sol, estilo fotorrealista",
  "aspect": "16:9",
  "referencePath": "reference_image/550e8400-e29b-41d4-a716-446655440000.webp"
}
```

**Respostas:**
- **201 Created**: Prompt aceito e encaminhado para o worker. Faça polling em GET /api/v1/images/:id até status=DONE.
```json
{
  "success": true,
  "id": 4821,
  "status": "PENDING",
  "remaining": 14,
  "limit": 100
}
```
- **400 Bad Request**: Campo 'prompt' ausente ou prompt com mais de 1000 caracteres.
```json
{
  "statusCode": 400,
  "statusMessage": "Campo 'prompt' é obrigatório"
}
```
- **429 Too Many Requests**: Limite de burst (5/min) ou limite diário atingido.
```json
{
  "statusCode": 429,
  "statusMessage": "Limite diário de 100 gerações atingido. Tente novamente amanhã."
}
```

**Notas:**
- Geração é assíncrona: o registro é criado com status PENDING e processado em background.
- Ciclo de status: PENDING → PROCESSING → GENERATING → DONE (ou ERROR).
- Limites diários por tier: ADMIN=200, planos padrão=100, planos 8/30=20.
- Burst limit: 5 gerações/minuto (ADMINs: 20/minuto). Compartilhado com o painel web.
- A URL da imagem gerada só está disponível quando status=DONE (campo url em GET :id).
- Para usar imagem de referência: primeiro faça POST /api/v1/images/reference (multipart/form-data, campo 'file') e passe a 'key' retornada como referencePath. Requer plano pago ou ADMIN (plano 8 retorna 403).

---

### POST https://darkvi.com/api/v1/images/reference
Faz upload de uma imagem de referência para ser usada na geração. Retorna a 'key' que deve ser passada como referencePath no POST /api/v1/images. Requer plano pago ou ADMIN (plano 8 retorna 403).

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```
Token gerado em darkvi.com/settings. Requer plano pago ou ADMIN.

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `file` | file | body | Sim | Arquivo de imagem a usar como referência. Formatos aceitos: PNG, JPEG, WebP. Tamanho máximo: 10 MB. A imagem é convertida para WebP (máx 1536×1536) antes do armazenamento. Ex: `(binário da imagem)` |

**Exemplo de requisição (body JSON):**
```json
"(multipart/form-data com campo 'file')"
```

**Respostas:**
- **200 OK**: Upload concluído. Use o campo 'key' como referencePath no POST /api/v1/images.
```json
{
  "success": true,
  "key": "reference_image/550e8400-e29b-41d4-a716-446655440000.webp",
  "url": "https://r2.example.com/reference_image/550e8400-e29b-41d4-a716-446655440000.webp"
}
```
- **400 Bad Request**: Nenhum arquivo enviado.
```json
{
  "statusCode": 400,
  "statusMessage": "Nenhum arquivo enviado"
}
```
- **403 Forbidden**: Plano atual (8) não tem acesso ao recurso de imagem de referência.
```json
{
  "statusCode": 403,
  "statusMessage": "Imagem de referencia nao disponivel no seu plano atual."
}
```
- **413 Payload Too Large**: Imagem excede 10 MB.
```json
{
  "statusCode": 413,
  "statusMessage": "Imagem deve ter no maximo 10 MB"
}
```
- **415 Unsupported Media Type**: Formato de imagem inválido ou corrompido.
```json
{
  "statusCode": 415,
  "statusMessage": "Formato de imagem invalido. Envie PNG, JPEG ou WebP."
}
```
- **429 Too Many Requests**: Burst limit de uploads atingido (10/min; ADMINs: 40/min).
```json
{
  "statusCode": 429,
  "statusMessage": "Limite de 10 uploads de referencia por minuto atingido."
}
```

**Notas:**
- Envie a requisição como multipart/form-data com o campo 'file' contendo o arquivo de imagem.
- A imagem é redimensionada para no máximo 1536×1536 px e convertida para WebP antes do armazenamento.
- A 'key' retornada deve ser passada como referencePath no POST /api/v1/images para usar a referência na geração.
- Disponível apenas para planos pagos e ADMIN. Plano 8 (gratuito) recebe 403.
- Burst limit: 10 uploads/minuto (ADMINs: 40/minuto).

---

### GET https://darkvi.com/api/v1/images/:id
Retorna o status e a URL assinada (quando DONE) de uma geração de imagem. Use em polling (recomendado: a cada 4s) até status=DONE para obter a url.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `id` | integer | path | Sim | ID numérico da geração, retornado pelo POST /api/v1/images. Ex: `4821` |

**Respostas:**
- **200 OK**: Dados da geração. Campo url preenchido apenas quando status=DONE.
```json
{
  "success": true,
  "id": 4821,
  "prompt": "Um dragão voando sobre montanhas nevadas ao pôr do sol, estilo fotorrealista",
  "status": "DONE",
  "aspect": "16:9",
  "url": "https://r2.example.com/signed-url...",
  "createdAt": "2026-06-06 14:00:00.000000",
  "updatedAt": "2026-06-06 14:01:23.000000"
}
```
- **400 Bad Request**: ID ausente ou não numérico.
```json
{
  "statusCode": 400,
  "statusMessage": "ID inválido"
}
```
- **404 Not Found**: Imagem não encontrada ou não pertence ao usuário autenticado.
```json
{
  "statusCode": 404,
  "statusMessage": "Imagem não encontrada"
}
```

**Notas:**
- status pode ser: PENDING | PROCESSING | GENERATING | DONE | ERROR.
- url é null enquanto status != DONE. Só faça fetch da imagem quando status=DONE.
- A URL assinada tem validade de 7 dias.

---

### GET https://darkvi.com/api/v1/images
Retorna a lista paginada de gerações de imagem do usuário autenticado, da mais recente para a mais antiga.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `page` | integer | query | Não | Página da listagem. Padrão: 1. Ex: `1` |
| `limit` | integer | query | Não | Itens por página. Padrão: 10. Máximo: 50. Ex: `10` |

**Respostas:**
- **200 OK**: Lista paginada de gerações. Campo url preenchido apenas em itens com status=DONE.
```json
{
  "success": true,
  "data": [
    {
      "id": 4821,
      "prompt": "Um dragão voando sobre montanhas nevadas ao pôr do sol, estilo fotorrealista",
      "status": "DONE",
      "aspect": "16:9",
      "url": "https://r2.example.com/signed-url...",
      "createdAt": "2026-06-06 14:00:00.000000",
      "updatedAt": "2026-06-06 14:01:23.000000"
    },
    {
      "id": 4820,
      "prompt": "Floresta tropical ao amanhecer",
      "status": "PENDING",
      "aspect": null,
      "url": null,
      "createdAt": "2026-06-06 13:55:00.000000",
      "updatedAt": "2026-06-06 13:55:00.000000"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 42,
    "totalPages": 5
  }
}
```

**Notas:**
- Itens com disable=1 (soft-deleted) são excluídos automaticamente.
- url é null para imagens ainda em processamento (PENDING/PROCESSING/GENERATING) ou com ERROR.
- A URL assinada tem validade de 7 dias.

---

### GET https://darkvi.com/api/tts/:id
Retorna os dados do texto/áudio gerado (textSpeech) pelo ID. Só permite acesso ao dono do áudio.

**Autenticação:** Bearer Token
```
Authorization: Bearer <SEU_TOKEN_DE_API>
```
O token deve estar associado a um usuário ativo.

**Parâmetros:**
| Parâmetro | Tipo | Onde | Obrigatório | Descrição |
|---|---|---|---|---|
| `id` | string (uuid) | path | Sim | ID do registro textSpeech. Ex: `4cb014d7-0061-42e4-8c09` |

**Respostas:**
- **200 OK**: Dados do áudio/texto encontrado.
```json
{
  "id": "4cb014d7-0061-42e4-8c09",
  "text": "Olá, isto é um teste...",
  "status": "DONE",
  "userId": "b2a8ec95-a83f-4551-985a-f5e47a830311",
  "createdAt": "2025-11-23T12:00:00.000Z",
  "updatedAt": "2025-11-23T12:02:10.000Z",
  "titulo": "Meu teste"
}
```
- **401 Unauthorized**: Token ausente ou inválido.
```json
{
  "ok": false,
  "error": true,
  "code": "AUTH_INVALID_TOKEN",
  "message": "Token inválido."
}
```
- **403 Forbidden**: O áudio não pertence ao usuário autenticado.
```json
{
  "ok": false,
  "error": true,
  "code": "FORBIDDEN",
  "message": "Esse áudio não pertence a você."
}
```
- **404 Not Found**: ID não informado ou áudio não encontrado.
```json
{
  "ok": false,
  "error": true,
  "code": "AUDIO_NOT_FOUND",
  "message": "audio não encontrado para este id."
}
```
