Enviar Arquivos PDF diretamente para o Storage

Criada por Alexandre Pateis, Modificado em Qui, 28 Mai na (o) 3:22 PM por Alexandre Pateis

Para grandes volumes de arquivos PDF, é possível realizar o envio diretamente ao storage.


Antes do envio, é necessário que exista um pedido registrado no sistema. Para isso, você pode utilizar um ID de pedido já existente ou criar um novo por meio da API.


Ao criar um pedido, é obrigatório informar:

  • ID da clínica;
  • ID do status do pedido.


Com o ID do pedido e as informações de metadata do arquivo PDF, é possível solicitar ao servidor os dados necessários para o envio ao storage.


A requisição deve ser feita para a URL:

https://max.cfaz.net/api/v1/archives/signed_url


O corpo da requisição deve conter:

  • request_id → ID do pedido ao qual o PDF será vinculado.
  • file_name Nome do arquivo PDF.
  • file_size Tamanho do arquivo em bytes.
  • content_type Para PDF, use application/pdf.
  • checksum MD5 do arquivo codificado em Base64.


Arquivo interno:


Para registrar o PDF como arquivo interno, informe is_hidden=true na etapa final de atualização do arquivo no Cfaz.

  • is_hidden=false → O PDF aparece na documentação do pedido.
  • is_hidden=true → O PDF aparece na aba de arquivos internos.


Cálculo do checksum:


O cálculo do checksum deve ser realizado da seguinte maneira:

  1. Ler o conteúdo binário do arquivo.
  2. Calcular o hash MD5 desse conteúdo.
  3. Codificar o resultado em Base64.
  4. Enviar esse valor como checksum.


Exemplo com CURL:


curl -X POST "https://max.cfaz.net/api/v1/archives/signed_url" \
  -H "Authorization: Bearer 62ed05b2bd52b20e5a1eff01a0b862e6" \
  -d "request_id=300196" \
  -d "file_name=arquivo.pdf" \
  -d "file_size=529058" \
  -d "checksum=KPnqX2hT1xqxyvR6BvaPjA==" \
  -d "content_type=application/pdf"


O retorno esperado é:


{
  "id": 875413,
  "headers": {
    "Content-MD5": "XE6RuyZgdUBewbbBjyx5g==",
    "Content-Disposition": "inline; filename=\"1544_paciente_last_Laudo_Ilustrado.pdf\"; filename*=UTF-8''1544_paciente_last_Laudo_Ilustrado.pdf",
    "Cache-Control": "public, max-age=31536000, immutable"
  },
  "signed_id": "eyJfcmFpbHMiOnsiZGF0YSI6MTI4MTUyNSwicHVyIjoiYmxvYl9pZCJ9fQ==--0f6f0c5a19f18be089f3192b40eb368beb296c12",
  "signed_url": "https://storage.googleapis.com/...",
  "download_url": "https://storage.googleapis.com/..."
}


Cada campo contém:

  • id → Identificador único do arquivo dentro do sistema. Esse é o ID do archive criado no Cfaz e será usado na URL da etapa final: /api/v1/archives/:id.
  • headers Cabeçalhos HTTP que devem ser utilizados ao enviar o PDF para o storage. Use exatamente os headers retornados nessa chave.
  • signed_id Identificador assinado do arquivo no ActiveStorage. Ele não é usado no upload para o storage; guarde esse valor para a etapa de atualização do arquivo no Cfaz.
  • signed_url URL para envio do PDF ao storage.
  • download_url URL temporária para download do PDF.


Enviar o PDF ao Storage:


Após receber a resposta da URL assinada, envie o conteúdo binário do PDF com PUT diretamente para o signed_url retornado pela API.


Não monte outra URL e não envie esse upload para /api/v1/archives/:id.


Use também todos os headers retornados no campo headers exatamente como vierem na resposta. Se a resposta retornar Content-MD5, Content-Disposition e Cache-Control, os três headers devem ser enviados no PUT.


Nesta etapa, use apenas:

  • signed_url → Como destino do PUT.
  • headers  Como cabeçalhos do PUT, usando todos os campos retornados.
  • arquivo PDF  Como corpo da requisição.

O signed_id não deve ser enviado para o storage. Ele será usado somente na próxima etapa, em archive[document], para informar ao Cfaz qual arquivo enviado ao storage deve ser vinculado ao pedido.


Exemplo:

curl -X PUT "<signed_url retornado pela API>" \
  -H "Content-MD5: XE6RuyZgdUBewbbBjyx5g==" \
  -H "Content-Disposition: inline; filename=\"1544_paciente_last_Laudo_Ilustrado.pdf\"; filename*=UTF-8''1544_paciente_last_Laudo_Ilustrado.pdf" \
  -H "Cache-Control: public, max-age=31536000, immutable" \
  --upload-file "arquivo.pdf"


No exemplo acima, os headers Content-MD5, Content-Disposition e Cache-Control foram usados porque apareceram em headers no retorno da API.



Atualizar o arquivo no Cfaz:


Após a conclusão do envio para o storage, é necessário atualizar o Cfaz para vincular o arquivo enviado ao pedido.


Essa etapa usa dois valores retornados na primeira requisição, em /api/v1/archives/signed_url:

  • id → Usado na URL /api/v1/archives/:id.
  • signed_id → Usado no campo archive[document].


Também é necessário informar novamente:

  • request_id → ID do pedido ao qual o PDF será vinculado.
  • archive[is_hidden] → Define se o PDF será arquivo comum ou arquivo interno.

Exemplo usando os valores retornados anteriormente:


{
  "id": 875413,
  "signed_id": "eyJfcmFpbHMiOnsiZGF0YSI6MTI4MTUyNSwicHVyIjoiYmxvYl9pZCJ9fQ==--0f6f0c5a19f18be089f3192b40eb368beb296c12"
}


Nesse caso:

  • Use 875413 na URL: /api/v1/archives/875413.
  • Use o signed_id em archive[document].

O arquivo só aparecerá no pedido depois que essa atualização for feita com sucesso.


Arquivo comum, visível na documentação do pedido:


curl -X PUT "https://max.cfaz.net/api/v1/archives/875413" \
  -H "Authorization: Bearer 62ed05b2bd52b20e5a1eff01a0b862e6" \
  -d "archive[request_id]=300196" \
  -d "archive[document]=eyJfcmFpbHMiOnsiZGF0YSI6MTI4MTUyNSwicHVyIjoiYmxvYl9pZCJ9fQ==--0f6f0c5a19f18be089f3192b40eb368beb296c12" \
  -d "archive[is_hidden]=false"


Arquivo interno:


curl -X PUT "https://max.cfaz.net/api/v1/archives/875413" \
  -H "Authorization: Bearer 62ed05b2bd52b20e5a1eff01a0b862e6" \
  -d "archive[request_id]=300196" \
  -d "archive[document]=eyJfcmFpbHMiOnsiZGF0YSI6MTI4MTUyNSwicHVyIjoiYmxvYl9pZCJ9fQ==--0f6f0c5a19f18be089f3192b40eb368beb296c12" \
  -d "archive[is_hidden]=true"

Após essa atualização, o PDF estará registrado no pedido.



Exemplo funcional com Python:

import base64
import hashlib
import os

import requests


# ====== Configurações ======

CFAZ_URL = "https://max.cfaz.net/api/v1"
TOKEN = ""
REQUEST_ID = 300196
CAMINHO_PDF = "arquivo.pdf"

# false = aparece na documentação do pedido
# true = aparece em arquivos internos
IS_HIDDEN = False


# ====== Utilitários ======

def calcular_checksum(caminho_arquivo):
    md5 = hashlib.md5()

    with open(caminho_arquivo, "rb") as arquivo:
        for bloco in iter(lambda: arquivo.read(1024 * 1024), b""):
            md5.update(bloco)

    return base64.b64encode(md5.digest()).decode("ascii")


def info_pdf(caminho_arquivo):
    return {
        "file_name": os.path.basename(caminho_arquivo),
        "file_size": os.path.getsize(caminho_arquivo),
        "checksum": calcular_checksum(caminho_arquivo),
        "content_type": "application/pdf",
    }


# ====== Etapa 1: solicitar URL assinada ======

def solicitar_url_assinada(cfaz_url, token, request_id, caminho_pdf):
    payload = {
        "request_id": request_id,
        **info_pdf(caminho_pdf),
    }

    response = requests.post(
        f"{cfaz_url}/archives/signed_url",
        json=payload,
        headers={"Authorization": f"Bearer {token}"},
        timeout=30,
    )

    response.raise_for_status()
    return response.json()


# ====== Etapa 2: enviar PDF ao storage ======

def enviar_para_storage(caminho_pdf, signed_url, headers):
    with open(caminho_pdf, "rb") as arquivo:
        response = requests.put(
            signed_url,
            data=arquivo,
            headers=headers,
            timeout=120,
        )

    response.raise_for_status()


# ====== Etapa 3: atualizar arquivo no Cfaz ======

def atualizar_arquivo_no_cfaz(cfaz_url, token, archive_id, request_id, signed_id, is_hidden=False):
    payload = {
        "archive": {
            "request_id": request_id,
            "document": signed_id,
            "is_hidden": is_hidden,
        }
    }

    response = requests.put(
        f"{cfaz_url}/archives/{archive_id}",
        json=payload,
        headers={"Authorization": f"Bearer {token}"},
        timeout=30,
    )

    response.raise_for_status()
    return response.json()


# ====== Fluxo completo ======

def enviar_pdf_para_cfaz(cfaz_url, token, request_id, caminho_pdf, is_hidden=False):
    dados_upload = solicitar_url_assinada(cfaz_url, token, request_id, caminho_pdf)

    enviar_para_storage(
        caminho_pdf,
        dados_upload["signed_url"],
        dados_upload.get("headers", {}),
    )

    return atualizar_arquivo_no_cfaz(
        cfaz_url,
        token,
        dados_upload["id"],
        request_id,
        dados_upload["signed_id"],
        is_hidden=is_hidden,
    )


# ====== Execução ======

if __name__ == "__main__":
    resultado = enviar_pdf_para_cfaz(
        CFAZ_URL,
        TOKEN,
        REQUEST_ID,
        CAMINHO_PDF,
        is_hidden=IS_HIDDEN,
    )

    print("PDF enviado e registrado com sucesso.")
    print(resultado)

Antes de executar, instale a dependência: pip install requests

Para enviar como arquivo interno, altere:

  • IS_HIDDEN = True

Para enviar como arquivo comum da documentação, mantenha:

  • IS_HIDDEN = False


Este artigo foi útil?

Que bom!

Obrigado pelo seu feedback

Desculpe! Não conseguimos ajudar você

Obrigado pelo seu feedback

Deixe-nos saber como podemos melhorar este artigo!

Selecione pelo menos um dos motivos
A verificação do CAPTCHA é obrigatória.

Feedback enviado

Agradecemos seu esforço e tentaremos corrigir o artigo