Boleto
Boleto de cobrança bancária and boleto de arrecadação: linha digitável and barcode validation, formatting, parsing and decoding.
Validate
- JavaScript library
- Python library
- Go library35 cases fail
- Ruby library35 cases fail
- Rust library35 cases fail
- .NET library31 cases fail
- Erlang library
Validates a boleto: the 47-digit cobrança bancária linha digitável or its 44-digit barcode, or a boleto de arrecadação as its 48-digit linha digitável or 44-digit barcode.
- The function verifies every check digit of the chosen layout (per Carta-Circular BCB 2.926/2000 and the FEBRABAN arrecadação layout).
- The código de moeda (position 4 of the barcode and of the linha digitável) must be
9(real), the only code Carta-Circular BCB 2.926/2000 assigns. 2.4.0 accepted any digit there. - The one exception is the FEBRABAN Convenção da Cobrança "Situação 2" slip of an institution identified only by its ISPB: bank code
988, código de moeda0, fator de vencimento0000, and the ISPB padded with zeros to 10 digits in barcode positions 10 to 19, where the amount would be. Bank988with código de moeda9is an ordinary slip. - The cobrança bancária barcode has 44 digits: bank code, código de moeda
9, the módulo 11 check digit in position 5, fator de vencimento, amount and free field. It is checked by the same rules as the linha digitável. Until 2.4.0 this barcode was rejected. - A 44-digit value that starts with
8is only ever an arrecadação barcode (the8is its product identifier). A cobrança bancária barcode of a bank code8xxis not accepted, because the two layouts could not be told apart. - The mask characters (whitespace,
.,-and/) are accepted between digits, a run of them included, and whitespace around the value. Any other character makes the value invalid: letters, punctuation or a mask character leading or trailing the digits. So a linha digitável wrapped in letters is rejected. Until 2.4.0 every non-digit was dropped. - A value that is not a string is invalid.
| Parameter | Type | Required |
|---|---|---|
value | string | yes |
| returns | boolean |
Check if a boleto (brazilian payment method) is valid.
- Accepts the 47 digit "cobrança bancária" linha digitável, its 44 digit barcode (bank code, código de moeda
9, the módulo 11 check digit in position 5, fator de vencimento, amount and free field) and, for the "boleto de arrecadação", either its 48 digit linha digitável or its 44 digit barcode. A 44 digit value starting with8is only ever an arrecadação barcode (the8is the FEBRABAN product identifier of the arrecadação), so a cobrança bancária barcode of a bank code from800to899(only804exists) is not accepted in barcode form, as the two could not be told apart; its 47 digit linha digitável is accepted. Up to 2.4.0 the cobrança bancária barcode was rejected. - The usual mask characters (whitespace,
.,-and/) are accepted between digits; any other character makes the value invalid, soabc+ a linha digitável +zzzis rejected, not read as its digits (up to 2.4.0 every non-digit was dropped). - The código de moeda (position 4 of the cobrança bancária barcode and linha digitável) must be
9(real), the only code Carta-Circular BCB nº 2.926/2000 assigns. The one exception is the "Situação 2" slip of the FEBRABAN Convenção da Cobrança, issued by an institution identified only by its ISPB: bank code988, código de moeda0, fator de vencimento0000and the ISPB, padded with zeros, where the amount would be. Any other digit is rejected.
import { isValidBoleto } from '@brazilian-utils/brazilian-utils';
isValidBoleto('00190000090114971860168524522114675860000102656'); // true
isValidBoleto('00196758600001026560000001149718606852452211'); // true (cobrança bancária barcode)
isValidBoleto('846100000005246100291102005460339004695895061080'); // true (boleto de arrecadação)
isValidBoleto('00170000010114971860168524522114275860000102656'); // false (código de moeda 7)
isValidBoleto('abc00190000090114971860168524522114675860000102656zzz'); // false (letters around the digits)
isValidBoleto('98800000060114971860168524522114100000018236120'); // true (Situação 2: bank 988, moeda 0, ISPB)Source: Carta-Circular BCB nº 2.926/2000, FEBRABAN, Layout Padrão de Arrecadação, Versão 08 (in force from 01/06/2026), FEBRABAN, Convenção da Cobrança.
Code: brazilian-utils/javascriptTry it with JavaScript isValidBoleto
Shared test cases (65) and the result in each library boleto.isValid
Format
- JavaScript library
- Python library
- Go library5 cases fail
- Ruby library7 cases fail
- Rust library1 case fails
- .NET library6 cases fail
- Erlang library
Formats a boleto linha digitável with its printed mask.
- The function groups the 47-digit cobrança bancária linha digitável as
00000.00000 00000.000000 00000.000000 0 00000000000000. - A 48-digit linha digitável starting with
8(boleto de arrecadação) gets four blocks of 11 digits, each followed by its check digit. The 44-digit arrecadação barcode keeps the cobrança bancária mask, and a 44-digit value starting with8is always read as an arrecadação barcode. - Every character that is not a digit is removed first, so a masked value is accepted. Digits beyond the length of the pattern are dropped.
- Without
options.pada short value is masked only as far as its digits go (104914gives10491.4). - A value with no digits (an empty string,
abc,null) gives an empty string, even withoptions.pad. Until 2.4.0pad: truereturned the full zero mask for an empty string or one without digits. options.padleft-pads the value with zeros to the length of the pattern before masking.- A number is read only when it is a safe non-negative integer. A negative, fractional, non-finite or unsafe number gives an empty string (2.4.0 read the digits of any number).
| Parameter | Type | Required |
|---|---|---|
value | string | number | yes |
options | FormatBoletoOptions | no |
options.pad | boolean | no |
| returns | string |
Format a boleto number.
- Options (
FormatBoletoOptions):padleft-pads the value with zeros to the length of the pattern before masking (defaultfalse). An empty value, or one without digits, gives''even withpad. - A 48 digit linha digitável starting with
8gets the arrecadação mask: four blocks of 11 digits, each followed by its check digit. The 44 digit arrecadação barcode keeps the "cobrança bancária" mask.
import { formatBoleto } from '@brazilian-utils/brazilian-utils';
formatBoleto('00190000090114971860168524522114675860000102656'); // 00190.00009 01149.718601 68524.522114 6 75860000102656
formatBoleto('1900000901149', { pad: true }); // 00000.00000 00000.000000 00000.000000 0 01900000901149
formatBoleto('846100000005246100291102005460339004695895061080'); // 84610000000-5 24610029110-2 00546033900-4 69589506108-0 (48 digit arrecadação linha digitável)
formatBoleto('84610000000246100291100054603390069589506108'); // 84610.00000 02461.002911 00054.603390 0 69589506108 (44 digit arrecadação barcode keeps the bancária mask)Source: FEBRABAN, Layout Padrão de Arrecadação, Versão 08 (in force from 01/06/2026).
Code: brazilian-utils/javascriptTry it with JavaScript formatBoleto
Shared test cases (71) and the result in each library boleto.format
Parse
- JavaScript library
- Python library
- Go library
- Ruby library2 cases fail
- Rust library
- .NET library1 case fails
- Erlang library
Removes every character that is not a digit from a boleto (mask, spaces, letters) and returns the digits, without checking that the boleto is valid.
- The result is cut to 47 digits, or to 48 when the digits start with
8(boleto de arrecadação). Digits beyond that are dropped. - A number is read only when it is a safe non-negative integer. A negative, fractional, non-finite or unsafe number gives an empty string (2.4.0 read the digits of any number).
| Parameter | Type | Required |
|---|---|---|
value | string | number | yes |
| returns | string |
Remove boleto formatting, keep only digits, and cap the result to 47 digits (48 for boleto de arrecadação).
import { parseBoleto } from '@brazilian-utils/brazilian-utils';
parseBoleto('00190.00009 01149.718601 68524.522114 6 75860000102656'); // 00190000090114971860168524522114675860000102656Source: Carta-Circular BCB nº 2.926/2000, FEBRABAN, Layout Padrão de Arrecadação, Versão 08 (in force from 01/06/2026).
Code: brazilian-utils/javascriptTry it with JavaScript parseBoleto
Shared test cases (10) and the result in each library boleto.parse
Generate
- JavaScript library
- Python library
- Go library
- Ruby library1 case fails
- Rust library
- .NET library
- Erlang library
Generates a valid random boleto number.
- By default, the function generates a 47-digit cobrança bancária linha digitável. With
params.typeset to arrecadação, it generates a 48-digit boleto de arrecadação instead. - A cobrança bancária slip gets a random 3-digit bank code, the código de moeda
9(real) and a fator de vencimento of0000(no due date) or1000to9999. Factors0001to0999denote no date and are never drawn. - A boleto de arrecadação draws its segment from 1 to 7 (segment 9 is the banks' own) and its value identifier from all four values (
6and8for an effective amount,7and9for a reference quantity), sohasEffectiveValuecan betrueor false. boleto.isValidaccepts the result.- It draws with
Math.random(), so it is not cryptographically secure. Do not use it for security purposes.
| Parameter | Type | Required |
|---|---|---|
params | GenerateBoletoParams | no |
params.type | "bancario" | "arrecadacao" | no |
| returns | string |
Generate a valid random boleto.
- Pass
{ type: 'arrecadacao' }(GenerateBoletoParams) for a 48 digit boleto de arrecadação instead of the default'bancario'(cobrança bancária, 47 digits). - A cobrança bancária slip carries the código de moeda
9and a fator de vencimento of0000(no due date) or1000to9999;0001to0999denote no date.
import { generateBoleto } from '@brazilian-utils/brazilian-utils';
generateBoleto(); // "00190000090114971860168524522114675860000102656"
generateBoleto({ type: 'arrecadacao' }); // "846100000005246100291102005460339004695895061080"Source: Carta-Circular BCB nº 2.926/2000, FEBRABAN, Layout Padrão de Arrecadação, Versão 08 (in force from 01/06/2026).
Code: brazilian-utils/javascriptTry it with JavaScript generateBoleto
Shared test cases (3) and the result in each library boleto.generate
Decode
- JavaScript library
- Python library
- Go library9 cases fail
- Ruby library10 cases fail
- Rust library
- .NET library
- Erlang library
Extracts the amount, due date and bank code from a boleto: the 47-digit linha digitável or the 44-digit barcode of a cobrança bancária slip, or a boleto de arrecadação. Returns null when the value is not a valid boleto.
- The result has
amount(in cents),expirationDateandbankCode(the 3-digit COMPE code). - The due date is
nullwhen the boleto carries no fator de vencimento (a factor below 1000). - The fator de vencimento cycle reset on 2025-02-22, so a factor maps to two dates 9000 days apart. No FEBRABAN or Banco Central publication tells the cycles apart; the rule comes from bank manuals.
options.referenceDateresolves the cycle as of that date instead of today. Pass it whenever the answer has to stay stable, since the same slip can resolve to the other date as time passes. - The window around
referenceDateis 3000 days back and 5500 days ahead, and the nearer candidate wins when neither falls inside it. A slip due up to 3499 days (about 9.5 years) beforereferenceDatekeeps its date. One due 3500 days (about 9.6 years) or more before it is read as the next cycle (a date in the future). To read an old slip, pass areferenceDatenear its issue date. The search never goes below the first cycle, so an olderreferenceDatestill resolves a factor to the oldest date it can denote, never one before the 1997-10-07 base date. - A
referenceDatethat is not a validDate(an invalid Date, a string, a number,null) is ignored and today is used. The call never throws. Until 2.4.0 an invalid Date gave the 1997 base date and a string or a number threw. - The 44-digit barcode is read for the same fields as the linha digitável: the amount from positions 10 to 19 and the fator de vencimento from positions 6 to 9. Until 2.4.0 a cobrança bancária barcode gave
null. A value that is not a string givesnull. - A 44-digit value that starts with
8is always read as an arrecadação barcode, never as a cobrança bancária one: it gives the arrecadação result when it is a valid arrecadação barcode andnullotherwise, even when it would be a valid barcode of a bank8xx. - A boleto de arrecadação has no bank code and no due date:
bankCodeis""andexpirationDateisnull. It also hastype("arrecadacao"),segment(1 to 7, or 9 for the banks' own use),value(the amount in reais,amountdivided by 100) andhasEffectiveValue(whether the amount is an effective value or a reference quantity). - A FEBRABAN "Situação 2" slip (bank
988, código de moeda0, seeboleto.isValid) carries the issuer's 8-digit ISPB where the amount would be. The result hasispbset to that ISPB,amountset to 0 andexpirationDatenull.ispbis new in 2.5.0 and is absent on every other slip. - It returns
nullexactly whenboleto.isValidreturnsfalse, so a slip with a código de moeda other than9givesnull(2.4.0 decoded it).
| Parameter | Type | Required |
|---|---|---|
value | string | yes |
options | GetBoletoInfoOptions | no |
options.referenceDate | Date | no |
| returns | BoletoInfo | null |
Extract information from a boleto (amount, expiration date, bank code). Returns null when the value is not a valid boleto.
- Options (
GetBoletoInfoOptions):referenceDateresolves the "fator de vencimento" cycle as of that date instead of now. - Reads the 47 digit linha digitável and the 44 digit barcode of a cobrança bancária slip, and the arrecadação forms, the same way as
isValidBoletoaccepts them. - Returns a
BoletoInfo:amountin cents,expirationDateand the three digitbankCode.expirationDateisnullwhen the slip carries no fator de vencimento (a factor below1000). - The fator de vencimento cycle reset on 22/02/2025, so a factor can mean either of two dates 9000 days apart. No FEBRABAN communiqué on the reset is published; the rule is in bank manuals, such as Bradesco's (Versão 17).
referenceDatepicks between them; pass it whenever the answer has to stay stable. - The windows are 3000 days back and 5500 days ahead of
referenceDate: a slip due up to 3499 days (about 9.5 years) before it keeps its date, and one due 3500 days (about 9.6 years) or more before it is read as the next cycle (a date in the future), so to read an old slip pass areferenceDatenear its issue date. AreferenceDatethat is not a validDateis ignored and now is used. - A boleto de arrecadação has
bankCode: ''andexpirationDate: null, plustype: 'arrecadacao',segment,value(the amount in reais) andhasEffectiveValue. - A FEBRABAN Convenção da Cobrança "Situação 2" slip (bank code
988, código de moeda0) carries the issuer's ISPB where the amount would be: it comes back asispb, withamount: 0.
import { getBoletoInfo } from '@brazilian-utils/brazilian-utils';
getBoletoInfo('00190000090114971860168524522114675860000102656');
// { amount: 102656, expirationDate: Date, bankCode: '001' }
getBoletoInfo('00196758600001026560000001149718606852452211');
// same slip read from its 44 digit barcode
getBoletoInfo('00190000090114971860168524522114675860000102656', {
referenceDate: new Date(2018, 6, 1)
});
// Resolves the fator de vencimento cycle as of 2018-07-01
getBoletoInfo('98800000060114971860168524522114100000018236120');
// { amount: 0, expirationDate: null, bankCode: '988', ispb: '18236120' }
getBoletoInfo('846100000005246100291102005460339004695895061080');
// { amount: 2461, expirationDate: null, bankCode: '', type: 'arrecadacao', segment: 4, value: 24.61, hasEffectiveValue: true }
getBoletoInfo('invalid'); // nullSource: Carta-Circular BCB nº 2.926/2000, FEBRABAN, Layout Padrão de Arrecadação, Versão 08 (in force from 01/06/2026), FEBRABAN, Convenção da Cobrança.
Code: brazilian-utils/javascriptTry it with JavaScript getBoletoInfo
Shared test cases (16) and the result in each library boleto.getInfo
Official sources
- bcb.gov.br/pre/normativos/…/c_circ_2926_v1_O.pdf
- cmsarquivos.febraban.org.br/Arquivos/documentos/…/Convenção da Cobrança - 05_02_2021_f.pdf
- cmsarquivos.febraban.org.br/Arquivos/documentos/…/Layout - Código de Barras - Versão 8 - 11_05_2026.pdf
- portal.febraban.org.br/pagina/3425/…/layout-febraban
See also Banks
Last updated on
