Criar Arquivo de Remessa
Criar Arquivo de Remessa
Seção intitulada “Criar Arquivo de Remessa”Gera um arquivo CNAB de remessa contendo todos os boletos pendentes de envio ao banco. O arquivo é retornado como texto plano no corpo da resposta e deve ser transmitido ao banco para registro dos boletos.
O Que Faz
Seção intitulada “O Que Faz”Este endpoint:
- Identifica automaticamente todos os boletos pendentes de remessa da conta bancária informada
- Gera um arquivo CNAB (240 ou 400) conforme configuração da conta
- Retorna o conteúdo do arquivo para download
- Marca os boletos como incluídos na remessa (não serão incluídos em remessas futuras)
Quando Usar
Seção intitulada “Quando Usar”Cenários Recomendados
Seção intitulada “Cenários Recomendados”| Cenário | Exemplo |
|---|---|
| Registro em lote | Registrar no banco todos os boletos gerados no dia |
| Integração via arquivo | Conta bancária configurada para troca de arquivos CNAB |
| Controle manual de envio | Decidir o momento exato de registrar os boletos no banco |
| Conciliação bancária | Manter controle dos boletos enviados por arquivo |
Pré-requisitos
Seção intitulada “Pré-requisitos”- Possuir uma conta bancária cadastrada com token válido
- Ter boletos criados que ainda não constam em nenhuma remessa
- Utilizar a nova forma de geração de boletos com
boleto.conta.token
Posição no Ciclo de Vida
Seção intitulada “Posição no Ciclo de Vida” ┌──────────────────┐ │ Criar Boletos │ POST /boletos │ com conta.token │ POST /carnes └────────┬─────────┘ POST /batch/boletos │ ▼ ┌──────────────────┐ │ ★ CRIAR REMESSA │ ◄── VOCÊ ESTÁ AQUI │ POST │ └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Enviar arquivo │ Internet Banking │ ao banco │ ou VAN └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Processar │ POST /arquivos/cnab/retornos │ Retorno │ └──────────────────┘Fluxo de Requisição
Seção intitulada “Fluxo de Requisição”Endpoint
Seção intitulada “Endpoint”POST https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessasProdução:
POST https://app.boletocloud.com/api/v1/arquivos/cnab/remessasHeaders da Requisição
Seção intitulada “Headers da Requisição”| Header | Valor | Obrigatório | Descrição |
|---|---|---|---|
Content-Type | application/x-www-form-urlencoded; charset=utf-8 | Sim | Tipo do conteúdo enviado |
Authorization | Basic {credenciais} | Sim | Autenticação HTTP Basic com API Key |
Corpo da Requisição (Form)
Seção intitulada “Corpo da Requisição (Form)”O corpo utiliza o formato application/x-www-form-urlencoded:
remessa.conta.token=api-key_SEU-TOKEN-DA-CONTACampos da Requisição
Seção intitulada “Campos da Requisição”| Campo | Tipo | Obrigatório | Tamanho | Formato | Descrição |
|---|---|---|---|---|---|
remessa.conta.token | string | Sim | 44 caracteres | api-key_{base64} | Token da conta bancária cadastrada na plataforma |
Validações
Seção intitulada “Validações”| Validação | Regra | Código | Mensagem |
|---|---|---|---|
| Campo obrigatório | remessa.conta.token não pode ser nulo ou vazio | 400 | Token da conta bancária é obrigatório |
| Formato válido | Token deve seguir o padrão api-key_{base64} | 400 | Token da conta bancária inválido |
| Conta existente | Token deve corresponder a uma conta cadastrada | 404 | Conta bancária não encontrada |
| Permissão | API Key deve ter acesso à conta bancária | 401 | Não autorizado |
| Boletos pendentes | Deve existir ao menos um boleto pendente | 204 | (sem corpo - nenhum boleto disponível) |
Respostas
Seção intitulada “Respostas”Sucesso: 201 Created
Seção intitulada “Sucesso: 201 Created”Indica que o arquivo de remessa foi gerado com sucesso.
Headers de Resposta
Seção intitulada “Headers de Resposta”| Header | Exemplo | Descrição |
|---|---|---|
X-BoletoCloud-Token | EX-abc123def456 | Token identificador do arquivo de remessa gerado |
Location | /api/v1/arquivos/cnab/remessas/EX-abc123... | URL para recuperação do arquivo via GET |
Content-Type | text/plain; charset=utf-8 | Tipo do conteúdo retornado |
Content-Disposition | inline; filename=CB070402.REM | Nome do arquivo gerado pelo sistema |
X-BoletoCloud-Version | 1.x.x | Versão da plataforma |
Corpo da Resposta
Seção intitulada “Corpo da Resposta”O corpo contém o conteúdo do arquivo CNAB em formato texto plano, pronto para ser salvo em disco e transmitido ao banco.
02RETORNO01COBRANCA 00000000000012345001EMPRESA XYZ...Sem Conteúdo: 204 No Content
Seção intitulada “Sem Conteúdo: 204 No Content”Indica que não existem boletos pendentes de remessa para a conta bancária informada.
- Nenhum corpo é retornado
- Nenhum arquivo é gerado
| Código | Status | Causa | Solução |
|---|---|---|---|
400 | Bad Request | Token da conta ausente ou formato inválido | Verifique o campo remessa.conta.token |
401 | Unauthorized | API Key inválida ou ausente | Verifique as credenciais de autenticação |
404 | Not Found | Conta não encontrada | Verifique se o token da conta está correto |
500 | Internal Server Error | Erro interno do servidor | Tente novamente ou contate o suporte |
Exemplo de Erro
Seção intitulada “Exemplo de Erro”{ "erro": { "status": 400, "mensagem": "Token da conta bancária é obrigatório" }}Comportamento com o Banco
Seção intitulada “Comportamento com o Banco”Formato do Arquivo
Seção intitulada “Formato do Arquivo”O formato CNAB é determinado pela configuração da conta bancária:
| Formato | Características | Bancos |
|---|---|---|
| CNAB 240 | Layout moderno, múltiplos segmentos | Maioria dos bancos |
| CNAB 400 | Layout legado, posições fixas | Alguns bancos específicos |
O Que Acontece Após o Envio
Seção intitulada “O Que Acontece Após o Envio”- Você envia o arquivo ao banco (via Internet Banking ou VAN)
- Banco processa o arquivo e registra os boletos
- Banco disponibiliza arquivo de retorno (geralmente no dia seguinte)
- Você processa o retorno via endpoint de retorno
- Boletos atualizados com status: REGISTRADO, REJEITADO, etc.
Tipos de Comunicação
Seção intitulada “Tipos de Comunicação”| Tipo | Usa Remessa? | Descrição |
|---|---|---|
| Arquivo CNAB | Sim | Envio manual via Internet Banking ou VAN |
| API/Webservice | Não | Registro automático via integração direta |
| VAN | Não | Envio automático via rede de valor agregado |
Exemplos de Código
Seção intitulada “Exemplos de Código”curl -X POST "https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas" \ -H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" \ -u "api-key_SUA-API-KEY:token" \ -d "remessa.conta.token=api-key_SEU-TOKEN-DA-CONTA" \ -o remessa.rem \ -vO arquivo será salvo como remessa.rem. Para obter o nome original gerado pelo sistema, verifique o header Content-Disposition na resposta.
import javax.ws.rs.client.ClientBuilder;import javax.ws.rs.client.Entity;import javax.ws.rs.core.Form;import javax.ws.rs.core.Response;import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;import java.io.InputStream;import java.nio.file.Files;import java.nio.file.Paths;import static javax.ws.rs.core.MediaType.WILDCARD;import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
public class CriarRemessa { public static void main(String[] args) throws Exception { // Dados para criação do arquivo remessa Form formData = new Form(); formData.param("remessa.conta.token", "api-key_SEU-TOKEN-DA-CONTA");
// Requisição para criação da remessa Response response = ClientBuilder.newClient() .target("https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas") .register(HttpAuthenticationFeature.basic( "api-key_SUA-API-KEY", "token" )) .request(WILDCARD) .post(Entity.form(formData));
// Dados da resposta System.out.println("HTTP Status: " + response.getStatus()); System.out.println("Token: " + response.getHeaderString("X-BoletoCloud-Token")); System.out.println("Location: " + response.getHeaderString("Location"));
// Identifica o resultado if (response.getStatus() == 201) { String contentDisposition = response.getHeaderString("Content-Disposition"); String fileName = contentDisposition.replaceAll(".*filename=", "").trim();
// Salva o arquivo no diretório corrente Files.copy( response.readEntity(InputStream.class), Paths.get(fileName), REPLACE_EXISTING ); System.out.println("Arquivo de remessa gerado: " + fileName);
} else if (response.getStatus() == 204) { System.out.println("Nenhum boleto pendente de remessa."); } else { System.err.println("Erro: " + response.readEntity(String.class)); } }}import okhttp3.*import java.io.File
fun main() { val client = OkHttpClient() val credential = Credentials.basic("api-key_SUA-API-KEY", "token")
val body = FormBody.Builder() .add("remessa.conta.token", "api-key_SEU-TOKEN-DA-CONTA") .build()
val request = Request.Builder() .url("https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas") .header("Authorization", credential) .post(body) .build()
client.newCall(request).execute().use { response -> println("Token: " + response.header("X-BoletoCloud-Token")) println("Location: " + response.header("Location"))
when (response.code) { 201 -> { val fileName = response.header("Content-Disposition") ?.replace(".*filename=".toRegex(), "")?.trim() ?: "remessa.rem" File(fileName).writeBytes(response.body!!.bytes()) println("Arquivo de remessa gerado: $fileName") } 204 -> println("Nenhum boleto pendente de remessa.") else -> println("Erro: " + response.code + " - " + response.body?.string()) } }}using System;using System.IO;using System.Net.Http;using System.Net.Http.Headers;using System.Text;using System.Threading.Tasks;
class Program{ static async Task Main(string[] args) { using var client = new HttpClient();
// Configurar autenticação Basic var credentials = Convert.ToBase64String( Encoding.ASCII.GetBytes("api-key_SUA-API-KEY:token")); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
// Preparar dados do formulário var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>( "remessa.conta.token", "api-key_SEU-TOKEN-DA-CONTA") });
// Fazer requisição var response = await client.PostAsync( "https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas", content);
Console.WriteLine("Token: " + response.Headers.GetValues("X-BoletoCloud-Token").FirstOrDefault());
if ((int)response.StatusCode == 201) { var fileName = response.Content.Headers.ContentDisposition?.FileName ?? "remessa.rem"; var bytes = await response.Content.ReadAsByteArrayAsync(); await File.WriteAllBytesAsync(fileName, bytes); Console.WriteLine("Arquivo de remessa gerado: " + fileName); } else if ((int)response.StatusCode == 204) { Console.WriteLine("Nenhum boleto pendente de remessa."); } else { var body = await response.Content.ReadAsStringAsync(); Console.WriteLine("Erro: " + (int)response.StatusCode + " - " + body); } }}const https = require('https');const fs = require('fs');
const data = 'remessa.conta.token=api-key_SEU-TOKEN-DA-CONTA';
const options = { hostname: 'sandbox.boletocloud.com', path: '/api/v1/arquivos/cnab/remessas', method: 'POST', auth: 'api-key_SUA-API-KEY:token', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 'Content-Length': Buffer.byteLength(data) }};
const req = https.request(options, (res) => { console.log('Token: ' + res.headers['x-boletocloud-token']); console.log('Location: ' + res.headers['location']);
if (res.statusCode === 201) { const match = (res.headers['content-disposition'] || '') .match(/filename=(.+)/); const fileName = match ? match[1].trim() : 'remessa.rem';
const file = fs.createWriteStream(fileName); res.pipe(file); file.on('finish', () => { console.log('Arquivo de remessa gerado: ' + fileName); }); } else if (res.statusCode === 204) { console.log('Nenhum boleto pendente de remessa.'); } else { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => console.log('Erro: ' + res.statusCode + ' - ' + body)); }});
req.write(data);req.end();package main
import ( "fmt" "io" "net/http" "os" "regexp" "strings")
func main() { data := "remessa.conta.token=api-key_SEU-TOKEN-DA-CONTA"
req, _ := http.NewRequest( "POST", "https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas", strings.NewReader(data), ) req.SetBasicAuth("api-key_SUA-API-KEY", "token") req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close()
fmt.Println("Token:", resp.Header.Get("X-BoletoCloud-Token")) fmt.Println("Location:", resp.Header.Get("Location"))
switch resp.StatusCode { case 201: re := regexp.MustCompile("filename=(.+)") match := re.FindStringSubmatch( resp.Header.Get("Content-Disposition")) fileName := "remessa.rem" if len(match) > 1 { fileName = strings.TrimSpace(match[1]) }
file, _ := os.Create(fileName) defer file.Close() io.Copy(file, resp.Body) fmt.Println("Arquivo de remessa gerado:", fileName)
case 204: fmt.Println("Nenhum boleto pendente de remessa.")
default: body, _ := io.ReadAll(resp.Body) fmt.Printf("Erro: %d - %s\n", resp.StatusCode, string(body)) }}<?php$url = 'https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas';$api_key = 'api-key_SUA-API-KEY';
$data = http_build_query([ 'remessa.conta.token' => 'api-key_SEU-TOKEN-DA-CONTA']);
$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $data);curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/x-www-form-urlencoded; charset=utf-8']);curl_setopt($ch, CURLOPT_USERPWD, "$api_key:token");curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HEADER, true);
$response = curl_exec($ch);$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);$headers = substr($response, 0, $header_size);$body = substr($response, $header_size);curl_close($ch);
// Extrair token do headerpreg_match('/X-BoletoCloud-Token:\s*(.+)/i', $headers, $tokenMatch);$token = trim($tokenMatch[1] ?? '');echo "Token: $token\n";
if ($http_code == 201) { preg_match('/filename=(.+)/', $headers, $matches); $filename = trim($matches[1] ?? 'remessa.rem'); file_put_contents($filename, $body); echo "Arquivo de remessa gerado: $filename\n";
} elseif ($http_code == 204) { echo "Nenhum boleto pendente de remessa.\n";
} else { echo "Erro ($http_code): $body\n";}?>import reimport requestsfrom requests.auth import HTTPBasicAuth
response = requests.post( 'https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas', auth=HTTPBasicAuth('api-key_SUA-API-KEY', 'token'), data={'remessa.conta.token': 'api-key_SEU-TOKEN-DA-CONTA'})
print('Token:', response.headers.get("X-BoletoCloud-Token"))print('Location:', response.headers.get("Location"))
if response.status_code == 201: match = re.search( r'filename=(.+)', response.headers.get('Content-Disposition', '') ) filename = match.group(1).strip() if match else 'remessa.rem'
with open(filename, 'wb') as f: f.write(response.content) print('Arquivo de remessa gerado:', filename)
elif response.status_code == 204: print('Nenhum boleto pendente de remessa.')
else: print('Erro:', response.status_code, '-', response.text)require 'net/http'require 'uri'
uri = URI('https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas')
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| request = Net::HTTP::Post.new(uri) request.basic_auth('api-key_SUA-API-KEY', 'token') request.set_form_data( 'remessa.conta.token' => 'api-key_SEU-TOKEN-DA-CONTA' )
response = http.request(request)
puts "Token: #{response['X-BoletoCloud-Token']}" puts "Location: #{response['Location']}"
case response.code when '201' filename = response['Content-Disposition'] &.match(/filename=(.+)/)&.[](1)&.strip || 'remessa.rem' File.write(filename, response.body) puts "Arquivo de remessa gerado: #{filename}"
when '204' puts 'Nenhum boleto pendente de remessa.'
else puts "Erro: #{response.code} - #{response.body}" endend(require '[clj-http.client :as client])
(let [response (client/post "https://sandbox.boletocloud.com/api/v1/arquivos/cnab/remessas" {:basic-auth ["api-key_SUA-API-KEY" "token"] :form-params {:remessa.conta.token "api-key_SEU-TOKEN-DA-CONTA"} :as :byte-array :throw-exceptions false})]
(println "Token:" (get-in response [:headers "X-BoletoCloud-Token"])) (println "Location:" (get-in response [:headers "Location"]))
(case (:status response) 201 (let [filename (or (second (re-find #"filename=(.+)" (get-in response [:headers "Content-Disposition"]))) "remessa.rem")] (clojure.java.io/copy (:body response) (clojure.java.io/file filename)) (println "Arquivo de remessa gerado:" filename))
204 (println "Nenhum boleto pendente de remessa.")
(println "Erro:" (:status response))))Exemplo Prático
Seção intitulada “Exemplo Prático”Cenário: Registro de Boletos do Dia
Seção intitulada “Cenário: Registro de Boletos do Dia”Uma empresa gera boletos ao longo do dia e ao final do expediente envia todos para registro no banco.
- Manhã: Criados 15 boletos via
POST /boletoscomboleto.conta.token - Tarde: Criados mais 8 boletos via
POST /boletos - Final do dia: Chamada a
POST /arquivos/cnab/remessascomremessa.conta.token - Resultado: Arquivo CNAB gerado com os 23 boletos pendentes
- Envio: Arquivo importado no Internet Banking do banco
- Dia seguinte: Banco disponibiliza arquivo de retorno
Resposta da API (Headers)
Seção intitulada “Resposta da API (Headers)”HTTP/1.1 201 CreatedX-BoletoCloud-Token: EX-abc123def456Location: /api/v1/arquivos/cnab/remessas/EX-abc123def456Content-Type: text/plain; charset=utf-8Content-Disposition: inline; filename=CB070402.REMX-BoletoCloud-Version: 1.0.0