ForSign.Sdk 2.0.2

dotnet add package ForSign.Sdk --version 2.0.2
                    
NuGet\Install-Package ForSign.Sdk -Version 2.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ForSign.Sdk" Version="2.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ForSign.Sdk" Version="2.0.2" />
                    
Directory.Packages.props
<PackageReference Include="ForSign.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ForSign.Sdk --version 2.0.2
                    
#r "nuget: ForSign.Sdk, 2.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ForSign.Sdk@2.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ForSign.Sdk&version=2.0.2
                    
Install as a Cake Addin
#tool nuget:?package=ForSign.Sdk&version=2.0.2
                    
Install as a Cake Tool

Documentação Completa do SDK ForSign para .NET (v2)

Bem-vindo à documentação oficial do SDK ForSign para .NET! A ForSign oferece a integração mais simples do mercado para assinaturas eletrônicas, tornando seus processos mais eficientes, seguros e amigáveis.

Este SDK foi projetado para ser intuitivo e poderoso, permitindo que você integre um fluxo de assinatura digital completo em sua aplicação .NET com o mínimo de esforço.

NuGet version License: MIT

✨ Principais Funcionalidades

  • Autenticação Simplificada: Conecte-se à nossa API usando apenas uma API Key.
  • Múltiplos Tipos de Assinatura: Suporte para clique, desenho, rubrica e carimbos personalizados.
  • Segurança Robusta: Valide a identidade dos Assinantes com duplo fator de autenticação (2FA) via E-mail.
  • Workflows Flexíveis: Defina a ordem de assinatura, datas de expiração e redirecionamento pós-assinatura.
  • Formulários Interativos: Colete dados estruturados diretamente no documento com campos de texto, checkboxes e listas de seleção.
  • Anexos Seguros: Solicite documentos adicionais (como RG, CNH) dos Assinantes durante o processo.
  • Gerenciamento Completo: Tenha controle total sobre o ciclo de vida das operações: finalize, cancele, baixe documentos e gerencie anexos.

⚙️ 1. Instalação e Configuração

Começar a usar o SDK ForSign é um processo rápido e direto.

Requisitos

  • .NET: O SDK é compatível com uma vasta gama de versões do .NET, incluindo .NET Framework 4.5+, .NET Standard 2.0+, e .NET 5 a 8.
  • IDE: Visual Studio, VS Code, ou JetBrains Rider.

Instalação via NuGet

Instale o SDK em seu projeto usando o gerenciador de pacotes NuGet.

# .NET CLI
dotnet add package ForSign.Sdk

# Package Manager Console
Install-Package ForSign.Sdk

Configurando suas Credenciais (API Key)

A autenticação com a API ForSign é feita através de uma API Key. Você pode gerar a sua no painel de desenvolvedor da ForSign.

using ForSign.Sdk;

// 1. Crie uma instância do cliente ForSign.
// (Recomendado: injetar como Singleton via DI em uma aplicação real)
var forsignClient = new ForSignClient();

// 2. Substitua "SUA_API_KEY_AQUI" pela chave obtida no painel.
const string API_KEY = "SUA_API_KEY_AQUI";

// 3. Crie o objeto de credencial.
var credential = new ApiKeyCredential(API_KEY);

// 4. Defina a credencial no cliente. O cliente usará esta chave em todas as chamadas.
forsignClient.SetCredential(credential);

Console.WriteLine("Cliente ForSign configurado com sucesso!");

⚠️ Dica de Segurança: Nunca exponha sua API Key em código de front-end ou em repositórios públicos. Utilize variáveis de ambiente, Azure Key Vault, AWS Secrets Manager ou outra ferramenta de gerenciamento de segredos para armazená-la de forma segura.


🚀 2. Guia Rápido: Sua Primeira Assinatura

Este guia mostra o fluxo completo para enviar um documento para assinatura em 4 passos simples.

Passo 1: Carregar o Documento

Primeiro, envie o documento PDF para a plataforma ForSign. O SDK oferece várias maneiras de fazer isso.

// Exemplo de upload a partir de uma URL pública
var fileRequest = await UploadFileRequest.AddFileFromUrlAsync(
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
    "contrato-exemplo.pdf"
);

// Envia o arquivo para a API
var uploadResponse = await forsignClient.UploadFileAsync(fileRequest);

// O objeto 'FileInformation' é essencial para os próximos passos
var fileInfo = new FileInformation(uploadResponse.Data.Id, uploadResponse.Data.FileName);

Console.WriteLine($"Arquivo '{fileInfo.FileName}' enviado! ID do Arquivo: {fileInfo.FileId}");

💡 Nota: Você pode carregar arquivos de um caminho local (AddFileFromPath), array de bytes (AddFileFromBytesAsync), Base64 (AddFileFromBase64Async) ou Stream (AddFileFromStreamAsync). Apenas arquivos PDF de até 10 MB são suportados.

É possivel enviar múltiplos arquivos em uma única operação. Basta repetir o processo de upload e adicionar todos os FileInformation ao Assinante.

Passo 2: Definir o Assinante

Um Signer representa uma pessoa que irá assinar o documento. Configure suas informações, notificações e, mais importante, a segurança.

using ForSign.Sdk.Enums;

var signer = new Signer
{
    Name = "João da Silva",
    Email = "joao.silva@exemplo.com", // Usado para notificações e como identificador

    // Como o Assinante será notificado para assinar?
    NotificationType = new EmailNotification("joao.silva@exemplo.com"),

    // ✨ RECOMENDADO: Adicione um método de Duplo Fator de Autenticação (2FA)
    // Um código de segurança será enviado para este e-mail antes da assinatura.
    DoubleAuthenticationMethod = new EmailDoubleAuthentication("joao.silva@exemplo.com"),

    // Que tipo de assinatura ele poderá usar?
    // SignatureType.UserChoice permite que o usuário escolha entre clique, desenho ou texto.
    SignatureType = new DefaultSignatureType(SignatureType.UserChoice)
};

// Onde no documento o João deve assinar?
// Adicione um campo de assinatura na página 1, posicionado a 70% da largura e 80% da altura.
signer.AddSignatureInPosition(fileInfo, 1, "70%", "80%");

Passo 3: Construir e Criar a Operação

Use o OperationRequestBuilder para montar a operação com todas as regras e informações.

var operationRequest = OperationRequestBuilder.InitializeWithName("Contrato de Prestação de Serviços")
    .SetExpirationDate(DateTime.Now.AddDays(15))
    .WithExternalId("ID-INTERNO-456") // Opcional: seu ID de referência
    .WithRedirectUrl("https://seusite.com/obrigado/{operationId}") // Redireciona após assinar (Verifique se seu plano suporta)
    .AddSigner(signer) // Adiciona o Assinante que configuramos
    .Build();

// Envia a requisição para a API da ForSign
var operationResponse = await forsignClient.CreateOperationAsync(operationRequest);

Passo 4: Obter e Usar a URL de Assinatura

A resposta da API contém as URLs de assinatura exclusivas para cada participante.

Console.WriteLine($"Operação criada com sucesso! ID da Operação: {operationResponse.Id}");

foreach (var member in operationResponse.Members)
{
    Console.WriteLine($"--- Assinante: {member.Name} ---");
    Console.WriteLine($"ID do Membro: {member.Id}");
    Console.WriteLine($"URL de Assinatura: {member.SignUrl}");
    Console.WriteLine("------------------------------------");
}

O que fazer com a URL? A url de assinatura pode ser enviada por e-mail, exibida em um botão na sua aplicação, ou redirecionada automaticamente. O Assinante acessa essa URL para revisar e assinar o documento. Ela será enviada também por e-mail se você configurou o NotificationType do Assinante.


📚 3. Guia de Funcionalidades Detalhado

Aprofunde-se nas funcionalidades mais poderosas do SDK.

3.1. Construindo a Operação (OperationRequestBuilder)

O OperationRequestBuilder é uma interface fluente para configurar sua operação.

var request = OperationRequestBuilder.InitializeWithName("Acordo de Confidencialidade")
    // Opcional: Define uma ordem de assinatura. O segundo Assinante só assina após o primeiro.
    .SetSignersOrderRequirement(true)
    
    // Define o idioma da interface de assinatura (pt-BR, en, es).
    .SetLanguage(Language.Portuguese)
    
    // Define que a operação só será finalizada manualmente via API ou painel.
    .SetManualFinish(true)
    
    // Adiciona um observador que recebe notificações, mas não assina.
    .AddObserver("advogado@empresa.com", "Dr. Advogado")
    
    // URL de redirecionamento com placeholders dinâmicos.
    .WithRedirectUrl("https://seuapp.com/status?op={operationId}&ref={externalId}")
    
    .AddSigner(signer1) // Ordem 1
    .AddSigner(signer2) // Ordem 2
    .Build();

3.2. Formulários Interativos

Colete informações diretamente no documento PDF.

using ForSign.Sdk.Forms;

// 1. Campo de Texto (para CPF, endereço, etc.)
var textField = TextFormField.WithName("CPF")
    .WithInstructions("Digite seu CPF")
    .IsRequired()
    .WithTextFormat(FrontTypeFormField.Number) // Define o tipo de dado
    .OnPosition(new FormFieldPosition(fileInfo, 1, "30%", "40%"))
    .WithValue("123.456.789-00"); // Valor pré-preenchido (opcional)

// 2. Caixa de Seleção (para aceite de termos)
var checkboxField = CheckboxFormField.WithName("Aceite dos Termos")
    .WithInstructions("Li e concordo com os termos de uso.")
    .IsRequired()
    .WithOptions(new List<string> { "Sim" })
    .OnPosition(new FormFieldPosition(fileInfo, 1, "30%", "50%"))
    .WithValue("Sim");

// 3. Lista Suspensa (Select)
var selectField = SelectFormField.WithName("Estado Civil")
    .IsRequired()
    .WithOptions(new List<string> { "Solteiro(a)", "Casado(a)", "Divorciado(a)" })
    .OnPosition(new FormFieldPosition(fileInfo, 1, "30%", "60%"));

// Adicione os campos ao Assinante
signer.AddFormField(textField);
signer.AddFormField(checkboxField);
signer.AddFormField(selectField);

3.3. Solicitando Anexos

Peça ao Assinante para enviar arquivos durante o processo de assinatura.

// Define um anexo obrigatório para o documento de identidade
var idAttachment = new Attachment("Documento de Identidade", "Envie uma foto do seu RG ou CNH", true);

// Define os tipos de arquivo permitidos
idAttachment.PermitFileType(AttachmentFileType.PNG);
idAttachment.PermitFileType(AttachmentFileType.JPEG);
idAttachment.PermitFileType(AttachmentFileType.PDF);

// Define como o usuário pode enviar o anexo
idAttachment.PermitAttachmentByInput(InputAttachmentType.UploadFile);       // Upload de arquivo
idAttachment.PermitAttachmentByInput(InputAttachmentType.CameraSideFront);  // Câmera frontal do celular
idAttachment.PermitAttachmentByInput(InputAttachmentType.CameraSideBack);   // Câmera traseira do celular

// Adiciona a solicitação de anexo ao Assinante
signer.RequestAttachment(idAttachment);

🎛️ 4. Gerenciando o Ciclo de Vida da Operação

Após a criação, você pode gerenciar a operação usando seu operationId.

Método Descrição
CompleteOperationAsync Finaliza uma operação que está aguardando conclusão manual.
CancelOperationAsync Cancela uma operação em andamento.
DownloadOperationZipAsync Baixa um arquivo .zip contendo os documentos assinados e a trilha de auditoria.
SetOperationManualCompletionAsync Muda o modo de finalização de uma operação para manual.
SetOperationAutomaticCompletionAsync Define uma data/hora para a finalização automática da operação.

4.1. Exemplos de Gerenciamento do Ciclo de Vida

Aqui estão exemplos práticos de como usar os métodos de gerenciamento. Assuma que forsignClient já está configurado e operationId é conhecido.

using ForSign.Sdk.Exceptions;
using System.IO;

long operationId = 12345; // ID da sua operação

// Exemplo 1: Finalizar uma operação manualmente
try
{
    var completeResponse = await forsignClient.CompleteOperationAsync(operationId);
    Console.WriteLine(completeResponse.Message);
}
catch (ForSignApiException ex)
{
    Console.WriteLine($"Erro ao finalizar: {ex.StatusCode} - {ex.Message}");
}

// Exemplo 2: Cancelar uma operação
try
{
    var cancelResponse = await forsignClient.CancelOperationAsync(operationId, "Cancelado por solicitação do departamento jurídico.");
    Console.WriteLine(cancelResponse.Message);
}
catch (ForSignApiException ex)
{
    Console.WriteLine($"Erro ao cancelar: {ex.StatusCode} - {ex.Message}");
}

// Exemplo 3: Baixar o pacote de documentos (ZIP)
try
{
    var zipResponse = await forsignClient.DownloadOperationZipAsync(operationId);
    
    // O SDK fornece um método auxiliar para salvar o arquivo
    string filePath = Path.Combine(Environment.CurrentDirectory, $"{zipResponse.Name}.zip");
    zipResponse.SaveToFile(filePath);
    Console.WriteLine($"Operação baixada e salva em: {filePath}");
}
catch (ForSignApiException ex)
{
    Console.WriteLine($"Erro ao baixar ZIP: {ex.StatusCode} - {ex.Message}");
}

📂 5. Gerenciando Anexos dos Assinantes

Se sua operação solicita anexos, você pode aprová-los, rejeitá-los ou baixá-los via API.

Método Descrição
GetMemberAttachmentsAsync Lista todos os anexos de um membro (participante) da operação.
ApproveAttachmentsAsync Aprova uma lista de anexos enviados por um membro.
RejectAttachmentsAsync Rejeita anexos, fornecendo um motivo para cada um.
DownloadAttachmentAsync Baixa o conteúdo de um anexo específico.

5.1. Exemplos de Gerenciamento de Anexos

Este fluxo de exemplo mostra como listar, aprovar/rejeitar e baixar anexos. Assuma que memberId é o ID de um participante da operação.

using ForSign.Sdk.Exceptions;
using ForSign.Sdk.Requests;
using System.Collections.Generic;
using System.IO;
using System.Linq;

long memberId = 56789; // ID do membro (participante)

try
{
    // 1. Listar anexos pendentes de um membro
    var attachments = await forsignClient.GetMemberAttachmentsAsync(memberId);
    var uploadedAttachments = attachments.Where(a => a.IsUploaded).ToList();

    if (!uploadedAttachments.Any())
    {
        Console.WriteLine("Nenhum anexo foi enviado por este membro ainda.");
        return;
    }

    Console.WriteLine($"Anexos enviados: {uploadedAttachments.Count}");

    // 2. Aprovar ou Rejeitar os anexos (lógica de exemplo)
    long firstAttachmentId = uploadedAttachments.First().Id;
    
    // Aprova o primeiro anexo
    await forsignClient.ApproveAttachmentsAsync(memberId, new List<long> { firstAttachmentId });
    Console.WriteLine($"Anexo ID {firstAttachmentId} aprovado.");

    // Rejeita outro anexo (se existir)
    if (uploadedAttachments.Count > 1)
    {
        long secondAttachmentId = uploadedAttachments[1].Id;
        var rejectedList = new List<RejectedAttachment>
        {
            new RejectedAttachment { Id = secondAttachmentId, Reason = "A imagem está com baixa resolução." }
        };
        await forsignClient.RejectAttachmentsAsync(memberId, rejectedList);
        Console.WriteLine($"Anexo ID {secondAttachmentId} rejeitado.");
    }

    // 3. Baixar um anexo aprovado para arquivamento
    var downloadResponse = await forsignClient.DownloadAttachmentAsync(firstAttachmentId);
    string filePath = Path.Combine(Environment.CurrentDirectory, downloadResponse.FileName);
    File.WriteAllBytes(filePath, downloadResponse.Content);
    Console.WriteLine($"Anexo '{downloadResponse.FileName}' baixado e salvo.");
}
catch (ForSignApiException ex)
{
    Console.WriteLine($"Erro no gerenciamento de anexos: {ex.StatusCode} - {ex.Message}");
}

🔌 6. Boas Práticas: Usando Webhooks

Para monitorar o status das suas operações em tempo real de forma eficiente, recomendamos o uso de Webhooks.

Como funciona?

  1. Você configura uma URL (um endpoint na sua aplicação) no painel de desenvolvedor da ForSign.
  2. A ForSign enviará uma notificação HTTP POST para essa URL sempre que um evento importante ocorrer (ex: Assinante assinou, operação finalizada, etc.).
  3. Sua aplicação recebe essa notificação e pode tomar ações automatizadas, como atualizar o status no seu banco de dados ou notificar o próximo Assinante.

Esta abordagem é muito superior a consultar o status de uma operação repetidamente (polling), pois é mais eficiente e fornece atualizações instantâneas.


📦 7. Exemplo de Código Completo

Este exemplo une todas as funcionalidades avançadas discutidas: 2FA, formulários, anexos e redirecionamento.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using ForSign.Sdk;
using ForSign.Sdk.Enums;
using ForSign.Sdk.Forms;
using ForSign.Sdk.Requests;

public class AdvancedSigningExample
{
    private const string API_KEY = "SUA_API_KEY_AQUI";

    public static async Task Main(string[] args)
    {
        // 1. Configuração do Cliente
        var client = new ForSignClient();
        client.SetCredential(new ApiKeyCredential(API_KEY));
        Console.WriteLine("Cliente configurado.");

        // 2. Upload do Documento
        var fileRequest = await UploadFileRequest.AddFileFromUrlAsync(
            "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", 
            "proposta-comercial.pdf"
        );
        var uploadResponse = await client.UploadFileAsync(fileRequest);
        var fileInfo = new FileInformation(uploadResponse.Data.Id, uploadResponse.Data.FileName);
        Console.WriteLine($"Documento '{fileInfo.FileName}' enviado com ID: {fileInfo.FileId}");

        // 3. Definição do Assinante com funcionalidades avançadas
        var signer = new Signer
        {
            Name = "Maria Souza",
            Email = "maria.souza@exemplo.com",
            NotificationType = new EmailNotification("maria.souza@exemplo.com"),
            DoubleAuthenticationMethod = new EmailDoubleAuthentication("maria.souza@exemplo.com"), // 2FA
            SignatureType = new DefaultSignatureType(SignatureType.UserChoice)
        };
        
        // Posição da assinatura
        signer.AddSignatureInPosition(fileInfo, 1, "50%", "80%");
        
        // Adicionando formulários
        var cargoField = TextFormField.WithName("Cargo")
            .IsRequired()
            .OnPosition(new FormFieldPosition(fileInfo, 1, "50%", "60%"));
        signer.AddFormField(cargoField);
        
        var termsCheckbox = CheckboxFormField.WithName("Aceite")
            .IsRequired()
            .WithOptions(new List<string> { "Concordo" })
            .OnPosition(new FormFieldPosition(fileInfo, 1, "50%", "70%"));
        signer.AddFormField(termsCheckbox);

        // Solicitando anexo
        var docAttachment = new Attachment("Contrato Social", "Anexe o contrato social da empresa", true);
        docAttachment.PermitFileType(AttachmentFileType.PDF);
        signer.RequestAttachment(docAttachment);
        Console.WriteLine("Assinante configurado com 2FA, formulários e anexo.");

        // 4. Construção e Criação da Operação
        var operationRequest = OperationRequestBuilder.InitializeWithName("Proposta Comercial - Empresa XYZ")
            .WithExternalId($"PROP-{Guid.NewGuid()}")
            .WithRedirectUrl("https://suaempresa.com/proposta-assinada?id={externalId}")
            .SetManualFinish(true)
            .SetLanguage(Language.Portuguese)
            .AddSigner(signer)
            .Build();
        
        var operationResponse = await client.CreateOperationAsync(operationRequest);
        Console.WriteLine("Operação criada com sucesso!");
        
        // 5. Exibição das URLs de Assinatura
        Console.WriteLine($"\nID da Operação: {operationResponse.Id}");
        foreach (var member in operationResponse.Members)
        {
            Console.WriteLine($"\nAssinante: {member.Name}");
            Console.WriteLine($"ID do Membro: {member.Id}");
            Console.WriteLine($"URL para Assinatura: {member.SignUrl}");
        }
    }
}

❓ Solução de Problemas

  • ForSignApiException: Esta é a exceção principal lançada pelo SDK quando a API retorna um erro. Inspecione a propriedade StatusCode e ErrorResponse para obter mais detalhes.
  • HttpStatusCode.Unauthorized (401): Sua API Key está incorreta ou expirou.
  • HttpStatusCode.PaymentRequired (402): Sua conta não possui créditos suficientes para realizar a operação.
  • HttpStatusCode.UnprocessableEntity (422): Os dados enviados na requisição são inválidos. Verifique a propriedade Messages na exceção para ver os erros de validação específicos de cada campo.
  • Erro de Tamanho de Arquivo: Certifique-se de que o PDF enviado não exceda 10 MB.
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 is compatible.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net45 is compatible.  net451 is compatible.  net452 is compatible.  net46 is compatible.  net461 is compatible.  net462 is compatible.  net463 was computed.  net47 is compatible.  net471 was computed.  net472 is compatible.  net48 is compatible.  net481 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.2 62 9/19/2025
2.0.1 83 9/19/2025
2.0.0 82 9/19/2025
1.0.6 249 2/2/2024
1.0.5 146 1/26/2024
1.0.4 121 1/26/2024
1.0.3 138 1/19/2024
1.0.2 128 1/19/2024
1.0.1 128 1/18/2024
0.1.4 127 1/26/2024

Version 2.0.2 includes significant improvements to error handling, particularly for API responses. We've added specific handling for HTTP 402 (Payment Required) status codes, which now clearly indicates when operations fail due to insufficient credits. This update enhances the developer experience by providing more descriptive error messages and better exception handling, especially in the create operation endpoint.