Assiny Gateway
Fragments

Referência do SDK

Toda a API do assiny.js no navegador, com as funções, as opções, os eventos, os retornos, os prazos, os erros e os avisos do console.

O assiny.js é o SDK do navegador do Assiny Gateway. Esta página lista tudo o que ele expõe; o que não está aqui não existe.

Carregar

<script src="https://sdk-gateway-js.assiny.com.br/v1/assiny.js"></script>

Só pela tag. O script define a função global Assiny.

Nada lança

Nenhuma função lança exceção e nenhuma promessa rejeita. Argumento inválido vira o evento loaderror (assíncrono, depois do mount) ou { error } na promessa. Uma exceção dentro de uma função sua passada a on() vai ao console.error e não para o SDK. Se a criação da instância falhar de forma inesperada, Assiny() devolve uma instância que não monta nada e responde { error } com unknown a toda promessa.

Assiny(publishableKey, options)

const assiny = Assiny('pk_test_...', { locale: 'pt-BR' });
ParâmetroValores
publishableKeya chave publicável, na forma pk_(test|live)_ seguida de letras e dígitos; o prefixo diz se é o Modo de teste ou o Modo real
options.locale'pt-BR' (padrão) ou 'en': os textos do fragment e da tela do QR e as message de erro; outro valor vale 'pt-BR', com aviso no console

Devolve a instância { fragments, createPaymentMethod, handleNextAction }. Com a chave aceita, Assiny() acrescenta ao body dois iframes invisíveis do SDK, que ficam na página; o recomendado é uma instância por página.

Chave recusada: nenhum iframe nasce, o mount emite loaderror com o código e toda promessa resolve { error } com ele.

codeQuando
invalid_publishable_keya chave não tem a forma acima; uma chave que começa com sk_ também ganha um aviso no console
insecure_pagea chave do Modo real numa página que não é https:, fora de localhost e 127.0.0.1
page_origin_invalida página não tem origem real (location.origin é "null"), como num iframe com sandbox sem allow-same-origin

assiny.fragments(options)

O objeto que assiny.fragments() devolve é o Fragments; o que fragments.create('payment') devolve é o Payment Fragment. As mensagens de erro usam esses dois nomes.

const fragments = assiny.fragments({
  mode: 'payment',
  amount: 12990,
  currency: 'brl',
  clientSecret, // opcional
  appearance, // opcional
  fonts, // opcional
});
OpçãoValoresCódigo, se inválida
mode'payment', obrigatóriomode_invalid
amounto total em centavos: inteiro seguro (Number.isSafeInteger) maior que zeroamount_invalid
currencyo código ISO 4217 em minúsculas de uma moeda que o navegador conhece (Intl), como 'brl'currency_invalid
clientSecretopcional: o client_secret do pagamento, na forma pi_..._secret_..., guardado para o handleNextActioninvalid_client_secret
appearanceopcional: Aparênciaitem inválido é ignorado com aviso
fontsopcional: [{ family, weights }] do catálogo (Aparência)item inválido é ignorado com aviso

Devolve { update, create }. Opção inválida não lança: o código chega pelo loaderror do mount. amount, currency e clientSecret se corrigem com fragments.update(): o fragment guarda o seletor do mount e monta quando o valor fica válido. mode não muda depois.

  • Um por instância: o segundo assiny.fragments() devolve um objeto cujo create() dá loaderror fragment_already_exists no mount e cujo update() resolve { error } com o mesmo código.
  • O PIX exige currency: 'brl': com 'pix' em paymentMethodTypes e outra moeda, o mount emite payment_method_types_invalid.
  • appearance e fonts entram só aqui; não há como trocá-los depois na mesma instância.

fragments.update(options)

const { error } = await fragments.update({ amount: 15990 });
OpçãoEfeitoCódigo, se inválida
amounto novo total; o fragment redesenha e refaz o Combinar (com partsFrom: 'page', as Partes voltam a valer só com um novo update({ parts }))amount_invalid
currencya nova moedacurrency_invalid; payment_method_types_invalid com PIX e moeda que não é 'brl'
clientSecretguarda o client_secret para o handleNextActioninvalid_client_secret
partsa divisão do Combinar, só com partsFrom: 'page' e o fragment montado: [{ method, amount }, { method, amount }], com amount de pelo menos 2 centavos, valores inteiros maiores que zero que somam o amount, métodos habilitados e a combinação card + card ou card + pix, nessa ordem, entre as que o combine deixaparts_invalid

Resolve {} ou { error }. Com amount e parts juntos, a soma é conferida contra o amount novo; dois update seguidos valem em ordem. Outros códigos:

codeQuando
parameter_invalido argumento não é um objeto
request_in_progresshá um createPaymentMethod ou um handleNextAction em curso
fragments_not_readyo SDK não carregou
fragment_already_existso update() de um segundo objeto fragments
mode_invalido assiny.fragments() nasceu com mode inválido
request_timeoutsem resposta em 2 s

Chave desconhecida é ignorada, com aviso no console.

fragments.create('payment', options)

const payment = fragments.create('payment', {
  paymentMethodTypes: ['card', 'pix'],
  combine: 'auto',
  partsFrom: 'component',
  fields: { billingDetails: { name: 'auto', address: { country: 'auto' } } },
  wallets: { applePay: 'auto' },
});
OpçãoValoresO que faz
paymentMethodTypeslista não vazia de 'card' e 'pix', obrigatóriaas abas, nessa ordem; a primeira começa selecionada; item repetido é removido com aviso no console
combine'auto' (padrão), 'never' ou lista de 'card_card' e 'card_pix'com 'auto', a aba Combinar métodos aparece com amount de pelo menos 2 centavos: "Cartão + Cartão" (card_card) com 'card', "Cartão + PIX" (card_pix) com 'card' e 'pix'; a lista oferece só as combinações listadas, na ordem de 'auto': ['card_card', 'card_pix'] com 'card' e 'pix' vale 'auto' (com só 'card', passe ['card_card']; a lista cheia é options_invalid) e [] vale 'never'
partsFrom'component' (padrão) ou 'page'com 'page', o fragment esconde o campo de valor do Combinar e mostra a divisão de fragments.update({ parts }); 'page' com combine: 'never' ou [] é options_invalid; Partes numa combinação fora da lista são parts_invalid
fields.billingDetails.name'auto' (padrão) ou 'never''never' esconde o campo Nome no cartão
fields.billingDetails.address.country'auto' (padrão) ou 'never''never' esconde o campo País
wallets.applePay'auto' (padrão) ou 'never'reservado: aceito e sem efeito nesta versão

Devolve { mount, unmount, on, off }. O primeiro argumento só aceita 'payment'. Os erros da criação chegam pelo loaderror do mount:

codeQuando
fragment_type_invalido tipo não é 'payment'
fragment_already_existsjá existe um fragment nesta instância, ou o create() é de um segundo objeto fragments
payment_method_types_invalidpaymentMethodTypes ausente, vazia ou com valor fora de 'card' e 'pix'
options_invalidas opções não são um objeto, uma chave é desconhecida, um valor está fora da lista, um item de combine é repetido, desconhecido ou não permitido por paymentMethodTypes (['card_pix'] sem 'pix'), ou partsFrom: 'page' com combine: 'never' ou []

Um create() com opções inválidas não ocupa o lugar do fragment da instância: um create() válido depois ainda funciona.

payment.mount(selector)

payment.mount('#pagamento');

selector é um seletor CSS que casa com exatamente um elemento. O fragment ocupa 100% da largura dele e a altura acompanha o conteúdo. O ready sai uma vez por mount. Elemento removido do DOM conta como desmontado. Os erros chegam pelo loaderror:

codeQuando
invalid_publishable_key, insecure_page, page_origin_invalida chave da instância foi recusada
o código do create()fragment_type_invalid, fragment_already_exists, payment_method_types_invalid ou options_invalid
mode_invalido mode do assiny.fragments() não é 'payment'
mount_target_not_foundo seletor não casa com exatamente um elemento
already_mountedo fragment já está montado
amount_invalid, currency_invalid, invalid_client_secret, payment_method_types_invalido assiny.fragments() tem um desses valores inválido, ou o PIX está com moeda que não é 'brl'; o fragment monta quando um fragments.update() corrige
fragments_not_readyo SDK ou o fragment não carregou em 10 s
request_timeouto SDK não respondeu à configuração (5 s) ou à montagem (10 s)
unknownuma falha inesperada

payment.unmount()

Remove o iframe do fragment e apaga o que foi digitado. Um createPaymentMethod em curso resolve { error } com fragments_not_ready. Depois, mount() monta de novo. Um handleNextAction em curso não para.

payment.on(event, handler) e payment.off(event, handler)

Ligam e desligam uma função num evento e devolvem o próprio payment. Nome fora da lista, ou handler que não é função, é ignorado.

EventoQuandoPayload
readyuma vez por mount, com o fragment configurado; não espera as fontes{ fragmentType: 'payment' }
changelogo depois do ready e a cada troca de aba, mudança de campo ou mudança do total{ fragmentType: 'payment', value: { type, save, parts }, complete, empty, error }
focuso foco entra no fragment{ fragmentType: 'payment' }
bluro foco sai do fragment{ fragmentType: 'payment' }
loaderroro fragment não montou{ fragmentType: 'payment', error: { type, code, message } }

O payload do change:

CampoTipoO que é
value.type'card', 'pix' ou 'combine'a aba selecionada
value.saveboolean, só com 'card'nesta versão, sempre false
value.parts[{ method, amount }, { method, amount }], só com 'combine'as Partes, quando o valor da primeira é maior que zero e menor que o total, mesmo com o cartão incompleto
completebooleancartão: número, validade e CVC completos e válidos; PIX: sempre true; Combinar: o valor válido e os cartões da combinação completos
emptybooleannada digitado; no PIX, sempre true
error{ code, message }, quando háo erro que está na tela

Nenhum evento traz o que foi digitado no cartão.

assiny.createPaymentMethod({ fragments, params })

const { parts, error } = await assiny.createPaymentMethod({
  fragments,
  params: { billing_details: { name, email, phone, tax_id, tax_id_type, address } },
});
  • fragments: o objeto devolvido pelo assiny.fragments() desta instância.
  • params.billing_details: os dados do pagador. Cada campo que você manda vale como veio, para todas as Partes; campo que você não manda entra do fragment se o campo correspondente está ligado ('auto') e preenchido: Nome no cartão em name, País em address.country, por cartão. Nada é sobrescrito; '', null e undefined contam como não mandado. No PIX, só o que você mandou. Chaves aceitas: name, email, phone, tax_id, tax_id_type e address com line1, line2, city, state, postal_code e country; outra chave é descartada, com aviso no console. Na política padrão, o pagador precisa de email no cartão e no PIX e de name no cartão; sem eles, a criação do método de pagamento ou o confirm recusa com payer_field_missing.

Resolve { parts: [{ method, amount, payment_method }] }, com method 'card' ou 'pix' e payment_method o pm_ criado, na ordem das Partes da aba selecionada (cartão ou PIX: uma Parte com o amount inteiro; Combinar: duas, que somam o amount), ou { error: { type, code, message, part } }, com part só quando a falha é de uma Parte.

O que acontece:

  • O fragment confere os campos da aba selecionada; campo incompleto ou inválido resolve um validation_error sem ir à API e mostra o erro no campo.
  • Enquanto os métodos são criados, os campos ficam desligados (.Input:disabled).
  • Um pm_ por Parte, em ordem; a primeira falha interrompe as seguintes e o erro diz em part o índice da Parte que falhou.
  • Depois de um { error }, o que foi digitado fica e o campo que a API apontou fica marcado; na nova tentativa, a Parte que não mudou reusa o pm_ já criado. Depois de um sucesso, a próxima chamada cria pm_ novos.
codeQuando
fragments_not_readyo fragments não é o desta instância, o fragment não está montado e pronto, ou houve unmount() durante a chamada
parameter_invalidparams não é um objeto ou não pode ser copiado; ou a API recusou um parâmetro
request_in_progresshá outro createPaymentMethod ou um handleNextAction em curso
os de validation_errorum campo do fragment, ou a divisão do Combinar (incomplete_parts, parts_invalid)
os de card_error e os outros da APIa resposta da API, pela tabela abaixo
request_timeout8 s sem resposta da API num pm_, ou 20 s na chamada inteira

assiny.handleNextAction({ clientSecret })

const { paymentIntent, error } = await assiny.handleNextAction({
  clientSecret: 'pi_..._secret_...',
});
  • clientSecret: o client_secret do pagamento, na forma pi_..._secret_.... O da chamada vence o guardado por assiny.fragments({ clientSecret }) ou fragments.update({ clientSecret }).
  • Funciona só com a instância de Assiny(): não precisa do fragment montado.

O SDK lê o pagamento a cada 3 s e segue o próximo passo, uma ação por vez, até o fim:

Status lidoO que o SDK faz
succeeded, canceled, requires_payment_method, requires_confirmationencerra e resolve { paymentIntent }; em succeeded com a tela do QR aberta, mostra o pagamento confirmado e fecha 4 s depois
processinglê de novo, sem desenhar
requires_action com o QR do PIXabre ou mantém a tela do QR do PIX (PIX e a tela do QR)
requires_action com outra ação, ou sem açãofecha a tela e resolve { error } com next_action_unsupported
qualquer outroresolve { error } com unknown

Esc ou Fechar na tela do QR param a leitura e resolvem { paymentIntent } com o estado da última leitura, em geral requires_action; uma nova chamada reabre a ação atual. Até a primeira leitura há 20 s; depois, a promessa vive enquanto a leitura vive.

Resolve:

{
  "paymentIntent": {
    "id": "pi_...",
    "object": "payment_intent",
    "livemode": false,
    "status": "succeeded",
    "amount": 12990,
    "currency": "brl",
    "parts": [
      { "id": "pip_...", "position": 1, "method": "pix", "amount": 12990, "status": "succeeded" }
    ],
    "last_payment_error": null
  }
}

parts traz id, position, method, amount e status de cada Parte; last_payment_error é { type, code, message } ou null. Sem next_action e sem os outros campos do pagamento.

codeQuando
invalid_client_secreto clientSecret não tem a forma pi_..._secret_...
client_secret_missingsem clientSecret na chamada e nenhum guardado
request_in_progresshá outro handleNextAction ou um createPaymentMethod em curso
fragments_not_readyo SDK não carregou
payment_intent_not_founda primeira leitura respondeu 404
o código da tabela abaixo, como api_key_invalid, permission_denied ou unknowna primeira leitura foi recusada
api_unavailablea primeira leitura falhou na rede, respondeu 500 ou mais, ou veio ilegível
request_timeout8 s sem resposta na primeira leitura, ou 20 s sem a primeira leitura
next_action_unsupportedo pagamento pede uma ação que o SDK não conhece
overlay_not_readya tela do QR não abriu em 10 s

Depois da primeira leitura, uma leitura que falha não encerra: o SDK tenta na volta seguinte e, depois de três falhas seguidas, a tela do QR mostra "Sem conexão. Tentando de novo.".

Prazos

O quêPrazoAo vencer
a configuração enviada pelo assiny.fragments()5 sloaderror com request_timeout
mount()10 sloaderror com request_timeout
unmount()2 snada visível: o iframe já saiu
fragments.update()2 s{ error } com request_timeout
createPaymentMethod(), a chamada inteira20 s{ error } com request_timeout
handleNextAction(), até a primeira leitura20 s{ error } com request_timeout
cada chamada à API (a criação de um pm_, uma leitura do pagamento)8 srequest_timeout; depois da primeira leitura, nova tentativa
o intervalo da leitura do pagamento3 s—
a carga do SDK, do fragment e da tela do QR10 sfragments_not_ready (SDK e fragment) ou overlay_not_ready (tela do QR)
a tela do QR depois do succeeded4 sfecha e resolve { paymentIntent }

Erros

{ type, code, message }, e part quando a falha é de uma Parte no createPaymentMethod. A message vem do catálogo do SDK, no locale da instância, nunca do servidor. A lista é fechada: um código fora dela chega como api_error unknown.

typecodemessage (pt-BR)
validation_errorincomplete_numberO número do cartão está incompleto.
validation_errorinvalid_numberO número do cartão é inválido.
validation_errorincomplete_expiryA validade do cartão está incompleta.
validation_errorinvalid_expiry_monthO mês de validade do cartão é inválido.
validation_errorinvalid_expiry_yearO ano de validade do cartão é inválido.
validation_errorincomplete_cvcO código de segurança está incompleto.
validation_errorinvalid_cvcO código de segurança é inválido.
validation_errorcard_brand_not_acceptedEsta bandeira não é aceita.
validation_errorincomplete_partsPreencha as duas partes do pagamento.
validation_errorparts_invalidA divisão do pagamento é inválida.
card_errorinvalid_numberO número do cartão é inválido.
card_errorincorrect_numberO número do cartão está incorreto.
card_errorinvalid_expiry_monthO mês de validade do cartão é inválido.
card_errorinvalid_expiry_yearO ano de validade do cartão é inválido.
card_errorinvalid_cvcO código de segurança é inválido.
card_errorcard_not_supportedEste cartão não é aceito.
invalid_request_errorpayer_field_missingFalta um dado do pagador.
invalid_request_erroremail_invalidO e-mail é inválido.
invalid_request_errormethod_not_supportedEste método de pagamento não é aceito.
invalid_request_errorparameter_invalidUm parâmetro enviado é inválido.
invalid_request_errorapi_key_invalidA chave de API é inválida.
invalid_request_errorpermission_deniedA chave de API não tem permissão para esta chamada.
invalid_request_errorinvalid_publishable_keyA chave publicável é inválida.
invalid_request_errorinsecure_pageUma chave live só funciona em página HTTPS.
invalid_request_errorinvalid_client_secretO client_secret é inválido.
invalid_request_erroramount_invalidO valor é inválido.
invalid_request_errorcurrency_invalidA moeda é inválida.
invalid_request_errormode_invalidO modo é inválido; use 'payment'.
invalid_request_errorpayment_method_types_invalidAs opções de pagamento são inválidas.
invalid_request_erroroptions_invalidAs opções do Payment Fragment são inválidas.
invalid_request_errorfragment_type_invalidTipo de Payment Fragment desconhecido; só 'payment' existe.
invalid_request_errorfragment_already_existsJá existe um Fragments ou Payment Fragment nesta instância.
invalid_request_errormount_target_not_foundO seletor do mount não casa com exatamente um elemento.
invalid_request_errorpage_origin_invalidA página precisa de uma origem real para montar o Payment Fragment.
invalid_request_errorfragments_not_readyO Payment Fragment não está montado e pronto.
invalid_request_erroralready_mountedO Payment Fragment já está montado.
invalid_request_errorrequest_in_progressJá existe uma chamada em andamento.
invalid_request_errorclient_secret_missingFalta o client_secret da Intenção.
invalid_request_errorpayment_intent_not_foundA Intenção de pagamento não foi encontrada.
api_errorapi_unavailableO serviço está indisponível; tente de novo.
api_errorrate_limitedMuitas tentativas; aguarde um pouco.
api_errorrequest_timeoutA chamada demorou demais.
api_errornext_action_unsupportedO próximo passo deste pagamento não é suportado.
api_erroroverlay_not_readyA janela do pagamento não abriu; tente de novo.
api_errorunknownOcorreu um erro inesperado.

Respostas da API

Como o SDK traduz a resposta da API em type e code. A message do servidor nunca é lida.

Na criação de cada pm_ (createPaymentMethod):

Resposta da APItype e code do SDK
400 card_error com invalid_number, incorrect_number, invalid_expiry_month, invalid_expiry_year, invalid_cvc ou card_not_supportedcard_error, o mesmo code
400 com payer_field_missing, email_invalid ou method_not_supportedinvalid_request_error, o mesmo code
400 com parameter_unknown, parameter_missing ou parameter_invalidinvalid_request_error parameter_invalid
401 api_key_invalidinvalid_request_error api_key_invalid
403 permission_deniedinvalid_request_error permission_denied
429api_error rate_limited
502, 503, 504, falha de rede, corpo sem o objeto error, sucesso sem um pm_api_error api_unavailable
8 s sem respostaapi_error request_timeout
qualquer outraapi_error unknown

Na leitura do pagamento (handleNextAction):

Resposta da APIO que o SDK faz
200 com o pagamentosegue
200 ilegívelapi_error api_unavailable
429não é erro: espera o Retry-After (em segundos ou data, no mínimo 1 s; sem ele, 3 s) e lê de novo
404invalid_request_error payment_intent_not_found
500 ou mais, falha de redeapi_error api_unavailable
8 s sem respostaapi_error request_timeout
400, 401, 403 e as demaisa tabela da criação

Na leitura, o erro só encerra o handleNextAction na primeira leitura; nas seguintes, o SDK tenta de novo.

Avisos no console

Os avisos saem só em pt-BR, com o prefixo [Assiny], e nunca trazem o que foi digitado.

QuandoAviso
uma chave sk_ no Assiny()[Assiny] Chave secreta no navegador: use a chave publicável pk_.
um locale desconhecido[Assiny] locale desconhecido: '…'; usando pt-BR.
um método repetido em paymentMethodTypes[Assiny] paymentMethodTypes repetido: '…' aparece mais de uma vez e foi deduplicado.
um item da aparência fora da lista ou da faixa[Assiny] Appearance: '…' foi ignorado (fora da lista fechada ou da faixa).
uma família ou um peso fora do catálogo[Assiny] Fonte: '…' foi ignorada (fora do catálogo).
uma chave fora do contrato em billing_details[Assiny] billing_details: a chave '…' foi descartada (fora do contrato).
uma chave desconhecida em fragments.update, createPaymentMethod.params ou handleNextAction[Assiny] fragments.update: a chave '…' foi ignorada (fora do contrato). (e o mesmo com createPaymentMethod.params e handleNextAction)

Nesta página