SEP-24SEP-6USDCStellarColômbia · COP

Anchor Stellar da VANK — Guia de integração

Conecte sua wallet ou exchange ao peso colombiano. Seus usuários convertem USDC ⇄ COP com pagamentos PSE na entrada e Bre-B na saída — a VANK cuida de compliance, KYC e liquidação.

1 · O que é o Anchor da VANK

Um anchor é a ponte entre a rede Stellar e o dinheiro local. O Anchor da VANK conecta USDC (o dólar digital emitido pela Circle) ao peso colombiano, usando os protocolos padrão do ecossistema Stellar: SEP-10 para autenticação e SEP-24 para depósitos e saques interativos.

⬇️ Depósito (on-ramp) · COP → USDC

Seu usuário paga pesos via PSE do banco dele e recebe USDC na conta Stellar. A VANK cobra o fiat, executa o compliance e entrega o USDC on-chain.

⬆️ Saque (off-ramp) · USDC → COP

Seu usuário envia USDC ao anchor e recebe pesos na hora na sua chave Bre-B — o sistema de pagamentos instantâneos da Colômbia. A cotação aparece antes de confirmar, sem spread oculto.

Sua integração fala os padrões do ecossistema: se sua wallet já se conecta a outros anchors (MoneyGram Ramps, por exemplo), conectar-se à VANK é o mesmo código apontando para outro domínio. E você escolhe a via: SEP-24, onde abre nosso formulário e nós guiamos o usuário, ou SEP-6, onde tudo vai por API e a tela é sua.

2 · Integração em 6 passos

  1. 1

    Comece na testnet — sem pedir permissão

    O sandbox está aberto: aponte sua integração para dev-stable-anchor.thisisvank.com e comece hoje. Escrever para nós vem depois, para ir à produção.

  2. 2

    Prepare sua wallet de testnet

    Uma conta Stellar na testnet com trustline para o USDC de teste. O emissor está no stellar.toml do ambiente de testes.

  3. 3

    Implemente SEP-10 e escolha sua via

    Primeiro a autenticação (SEP-10). Depois você escolhe uma de duas: com SEP-24 você abre nosso formulário e nós guiamos o usuário, o que são poucas linhas com o Stellar Wallet SDK. Com SEP-6 tudo vai por API e a tela é sua. O código de ambas está abaixo, e o SEP-6 tem sua própria seção.

  4. 4

    Certifique na testnet

    Três casos que você mesmo executa: um depósito, um saque e um saque com devolução. Na seção 7 está o que cada um prova e o que verificamos.

  5. 5

    Aprovação

    A VANK revisa sua certificação e seu caso de uso, e coordena com você o acordo de integração.

  6. 6

    Produção

    Você entrega o domínio definitivo do seu app e passa para a mainnet: anchor.thisisvank.com, com o USDC da Circle.

3 · Iniciando uma transação

SEP-1 · stellar.toml

Tudo começa no stellar.toml do ambiente: ali estão TODOS os endpoints que você vai usar, a chave com que o anchor assina e o ativo suportado. Não fixe nenhum desses valores no código — leia-os do toml, que é a fonte da verdade e muda entre ambientes.

Campo do tomlProtocoloPara que você precisa
WEB_AUTH_ENDPOINTSEP-10Autenticar-se. É o primeiro passo de todo o resto.
TRANSFER_SERVERSEP-6Depósito e saque via API, sem nosso formulário. É o endpoint da seção 5. Este campo também informa se o SEP-6 está habilitado nesse ambiente: se o toml o publica, está.
TRANSFER_SERVER_SEP0024SEP-24Depósito e saque abrindo nosso formulário.
KYC_SERVERSEP-12Identidade do usuário. E no saque via SEP-6, é por aqui que viaja a chave Bre-B de destino.
ANCHOR_QUOTE_SERVERSEP-38Cotações firmes, para garantir a taxa ao seu usuário.
SIGNING_KEYSEP-10A chave pública com que o anchor assina o challenge. Verifique-a.
CURRENCIESSEP-1O USDC suportado e seu EMISSOR, que muda entre testnet e produção.
Testes (testnet)Produção (mainnet)
Domínio do anchordev-stable-anchor.thisisvank.comanchor.thisisvank.com
stellar.toml/.well-known/stellar.toml/.well-known/stellar.toml
RedeStellar testnetStellar mainnet
Emissor de USDCde teste — leia do tomlCircle
⚠️ O emissor do USDC muda entre ambientes. Leia sempre do stellar.toml — nunca deixe fixo no código.
curl
# Leia o stellar.toml do ambiente — é a fonte da verdade
curl https://dev-stable-anchor.thisisvank.com/.well-known/stellar.toml   # produção: anchor.thisisvank.com

SEP-10 · Autenticação

SEP-10 prova que você controla a conta Stellar: você pede um challenge, assina e troca por um JWT que autoriza as demais chamadas. Atenção a isto, que é o mais esquecido: o challenge é assinado com DUAS chaves. A da conta do usuário, que diz quem opera, e a do SEU DOMÍNIO, que diz qual app o origina. A segunda é requisito de acesso e está explicada abaixo.

curl
# Sem o SDK, o SEP-10 são duas chamadas (qualquer linguagem):
GET  https://dev-stable-anchor.thisisvank.com/auth?account=G...        # → { transaction, network_passphrase }
#    Verifique o challenge ANTES de assinar: read_challenge_transaction(xdr, SIGNING_KEY do toml, passphrase, home_domain, web_auth_domain) no SDK da sua linguagem
#    Assine com a chave da conta (e com a do seu domínio se enviou client_domain)
POST https://dev-stable-anchor.thisisvank.com/auth   {"transaction": "<xdr firmado>"}   # → { token }  (JWT, 24 h)
shell
yarn add @stellar/typescript-wallet-sdk
Identidade do seu app (client_domain) — no sandbox é OPCIONAL (você pode autenticar só com a chave da conta e seguir); para produção é obrigatório: seu domínio deve publicar seu próprio stellar.toml em https://seu-dominio/.well-known/stellar.toml com uma SIGNING_KEY, e sua autenticação SEP-10 deve enviar esse clientDomain (seu backend co-assina o challenge com essa chave; o Wallet SDK suporta isso nativamente). É o mecanismo padrão do ecossistema — o mesmo que você usa com outros anchors — e é como o anchor sabe, com prova criptográfica e não por declaração, qual wallet origina cada transação.
TypeScript
import { Wallet, SigningKeypair, DomainSigner } from "@stellar/typescript-wallet-sdk";

const HOME_DOMAIN = "dev-stable-anchor.thisisvank.com"; // testes · produção: anchor.thisisvank.com
const CLIENT_DOMAIN = "tu-dominio.com";                 // o seu, o que publica sua SIGNING_KEY

async function authenticate(authSecretKey: string) {
  const wallet = Wallet.TestNet(); // produção: Wallet.MainNet()
  const anchor = wallet.anchor({ homeDomain: HOME_DOMAIN });
  const sep10 = await anchor.sep10();
  const authKey = SigningKeypair.fromSecret(authSecretKey);

  // Seu backend co-assina o challenge com a chave do seu domínio.
  // A chave SECRETA nunca sai de lá, nem chega ao navegador.
  const walletSigner = new DomainSigner("https://" + CLIENT_DOMAIN + "/sign", {});

  return await sep10.authenticate({
    accountKp: authKey,
    walletSigner,
    clientDomain: CLIENT_DOMAIN,
  });
}

O /sign é seu e vive no seu backend. Recebe o challenge, assina com a chave secreta do seu domínio e devolve. Essa chave secreta nunca sai do seu servidor nem chega ao navegador — por isso quem assina é o backend e não o cliente:

TypeScript
// No SEU backend. Recebe o challenge, assina com a chave do seu domínio e devolve.
// POST /sign  →  { transaction, network_passphrase }
import { Transaction, Keypair } from "@stellar/stellar-sdk";

app.post("/sign", (req, res) => {
  const { transaction, network_passphrase } = req.body;
  const tx = new Transaction(transaction, network_passphrase);
  tx.sign(Keypair.fromSecret(process.env.CLIENT_DOMAIN_SECRET!)); // a secreta da sua SIGNING_KEY
  res.json({ transaction: tx.toXDR(), network_passphrase });
});

O arquivo é mínimo — isto é TUDO o que ele precisa conter:

toml
# https://seu-dominio/.well-known/stellar.toml
VERSION = "2.7.0"
SIGNING_KEY = "G...A_CHAVE_PUBLICA_DO_SEU_APP"
  • SIGNING_KEY é a chave PÚBLICA de um par Stellar que sua equipe controla. A secreta nunca é publicada: é a que seu backend usa para co-assinar o challenge SEP-10.
  • Gere o par com o SDK ou o Stellar Lab. A conta não precisa de fundos nem existir on-chain — ela apenas identifica seu app.
  • Deve responder por https público, exatamente nesse caminho, sem autenticação e com CORS aberto (Access-Control-Allow-Origin: *). O anchor o consulta a cada autenticação.
  • Seu app já publica um stellar.toml por outros motivos? Ótimo: apenas garanta que ele inclua SIGNING_KEY — nenhum outro campo é necessário para se conectar à VANK.

SEP-24 · Depósito e saque interativos

A chamada retorna uma URL e um id. Você abre a URL em um webview e ali o usuário vê o detalhamento completo antes de confirmar: a taxa final, a comissão e o IVA SEPARADAMENTE, o total líquido que vai receber, e um contador com o tempo real restante dessa taxa. Nada fica escondido dentro do preço. O id é sua referência para consultar o status.

TypeScript
// Saque (off-ramp): o usuário envia USDC e recebe COP
const { url, id } = await anchor.sep24().withdraw({
  authToken,
  withdrawalAccount: USER_STELLAR_PUBLIC_KEY,
  assetCode: "USDC",
  lang: "pt",
});
// Abra `url` em um webview: a UI da VANK guia o resto
TypeScript
// Depósito (on-ramp): o usuário paga COP (PSE) e recebe USDC
const { url, id } = await anchor.sep24().deposit({
  authToken,
  destinationAccount: USER_STELLAR_PUBLIC_KEY,
  assetCode: "USDC",
  lang: "pt",
});
O link deve ser aberto dentro de 10 minutos após solicitá-lo: é quanto tempo seu token vive. Uma vez aberto, o formulário continua funcionando mesmo que o token expire — o limite é abri-lo, não concluí-lo. E uma transação parada em «incomplete» é um formulário aberto e não enviado: não a trate como uma operação em andamento.

4 · Status e sua ação em cada um

Acompanhe o status com o watcher do SDK (recomendado) ou com o endpoint bruto. Não há webhooks para a sua URL: o parâmetro on_change_callback é aceito mas não dispara nada, então consulte. Um 403 diz só forbidden: o JWT falta, é inválido ou venceu (dura 24 h); refaça o SEP-10. O ciclo é o padrão SEP-24:

TypeScript
const watcher = anchor.sep24().watcher();
const { stop } = watcher.watchOneTransaction({
  authToken,
  assetCode: "USDC",
  id: transactionId,
  onMessage: (tx) => {
    if (tx.status === "pending_user_transfer_start") {
      // Saque: envie o USDC agora. Depósito: aguarde o pagamento do usuário
    }
  },
  onSuccess: (tx) => { /* completed */ },
  onError: (tx) => { /* error */ },
});
curl
# Sem o SDK: iniciar e consultar (sandbox; produção: anchor.thisisvank.com)
curl -X POST "https://dev-stable-anchor.thisisvank.com/sep24/transactions/deposit/interactive" \
  -H "Authorization: Bearer $SEP10_JWT" -H "Content-Type: application/json" \
  -d '{"asset_code":"USDC","account":"G...","lang":"es"}'      # ou /withdraw/interactive → { url, id }

curl "https://dev-stable-anchor.thisisvank.com/sep24/transaction?id=$TRANSACTION_ID" \
  -H "Authorization: Bearer $SEP10_JWT"
StatusO que significaSua ação
incompleteO formulário foi aberto e ainda não enviado.Nada. NÃO expira sozinha: fica ali indefinidamente. Se seu usuário a abandonou, inicie outra — e para retomá-la é preciso pedir o link de novo.
pending_user_transfer_startSaque: o anchor aguarda seu USDC. Depósito: aguarda o pagamento PSE do usuário.Saque: envie o USDC para a conta e memo fornecidos pela transação. Depósito: nada.
pending_anchorA VANK recebeu os fundos e está processando.Nada — continue acompanhando.
pending_externalSaque: os pesos estão a caminho via Bre-B.Nada — normalmente segundos. Se o provedor falhar, a transação passa a error e a devolução sai sozinha.
completedEntregue: COP na conta do usuário ou USDC na wallet dele.Mostre o comprovante (more_info_url).
errorA operação não pôde ser concluída.Mostre o motivo; se USDC foi recebido, a devolução é automática.

Devoluções

Se um saque não puder ser concluído após o recebimento do USDC, a devolução para a conta de origem é automática, sem intervenção humana e pelo valor integral: o serviço não foi prestado, então nenhuma taxa é descontada.

Compliance

Cada operação passa por verificação de identidade e screening do beneficiário (listas restritas, PEP, OFAC) antes de mover dinheiro. O controle é fail-closed: se a verificação não puder rodar, a operação não avança.

5 · SEP-6: a via por API

Tudo acima usa SEP-24: seu app abre nosso formulário e nós guiamos o usuário. Com SEP-6 seu app solicita, pergunta e confirma via API, e a tela é sua. O SAQUE é inteiramente programático: nada é aberto. O DEPÓSITO termina em um link, e não por escolha nossa: o pagamento em pesos é feito via PSE, onde a pessoa escolhe seu banco, então não existe URL de pagamento antes dessa escolha. Abaixo está exatamente de onde sai esse link.

⚠️ O SEP-6 é habilitado por ambiente, e o próprio stellar.toml informa sem que você precise perguntar: se publica TRANSFER_SERVER, o SEP-6 está disponível ali; se não publica, ainda não. O ambiente de testes já o serve. Verifique no toml antes de apontar sua integração para um ambiente novo — é a mesma regra que você já aplica ao emissor do USDC. O SEP-24 está disponível em todos.
O que mais confunde na integração no SEP-6 a solicitação de saque NÃO leva o destino. Para onde o dinheiro vai viaja à parte, via SEP-12, no campo padrão bank_account_number, e pedimos a cada saque: nunca reutilizamos o anterior. Envie com transaction_id; se enviar sem ele, o saque dessa conta que estiver esperando a chave o toma. E atenção a quem é quem nesse SEP-12: os campos de identidade (nome, documento, e-mail) são do SEU USUÁRIO, quem saca, assim como no SEP-24 ele os digita no nosso formulário. Do BENEFICIÁRIO você só envia a chave: nome e documento nós resolvemos no diretório Bre-B e verificamos à parte. Devolvemos em message para você mostrar ao seu usuário antes de assinar. São duas verificações sobre duas pessoas, de propósito, quem envia e quem recebe: nenhuma delas pode ter problemas legais.

O que instalar

shell
npm install @stellar/stellar-sdk        # assinar SEP-10 e o pagamento on-chain
# Nada mais: o resto do SEP-6 são chamadas HTTP normais (fetch).

Um saque, passo a passo

Autentique-se primeiro com SEP-10, igual ao passo 3 deste guia. O resto são chamadas HTTP:

TypeScript
const ANCHOR = "https://dev-stable-anchor.thisisvank.com";   // SEP-6 vive HOJE no ambiente de testes
const auth = { Authorization: `Bearer ${authToken}` };   // JWT do SEP-10 (passo 3)

// 1) Solicite o saque. Retorna um id; você ainda NÃO pode enviar o USDC.
const { id } = await fetch(
  `${ANCHOR}/sep6/withdraw?asset_code=USDC&account=${account}&amount=2&type=breb`,
  { headers: auth },
).then((r) => r.json());

// 2) Consulte a transação e REAJA ao seu status.
const tx = async () =>
  (await fetch(`${ANCHOR}/sep6/transaction?id=${id}`, { headers: auth }).then((r) => r.json()))
    .transaction;

// Recém-criada está em incomplete: espere o PRIMEIRO ciclo do motor (até ~30 s) antes de decidir algo. Se perguntar só uma vez agora, pula o próximo passo.
let t = await tx();
while (t.status === "incomplete") { await sleep(5000); t = await tx(); }
if (t.status === "pending_customer_info_update") {
  // 3) Faltam dados. PERGUNTE quais — nunca adivinhe.
  const need = await fetch(
    `${ANCHOR}/sep12/customer?account=${account}&transaction_id=${id}`,
    { headers: auth },
  ).then((r) => r.json());
  console.log(need.fields);   // cada campo traz uma descrição para seu usuário

  // 4) Envie-os ATRELADOS a esta transação. bank_account_number = a chave Bre-B.
  await fetch(`${ANCHOR}/sep12/customer`, {
    method: "PUT",
    headers: { ...auth, "Content-Type": "application/json" },
    body: JSON.stringify({
      account,
      transaction_id: id,
      type: "sep6-withdrawal",   // contexto de saque: assim o SEP-12 sabe que a chave é necessária
      // SEU USUÁRIO, quem saca. O mesmo que ele digita no nosso formulário no SEP-24.
      first_name: "Ana", last_name: "Pérez",
      email_address: "ana@example.com",
      id_type: "CC", id_number: "1000000001",
      // O BENEFICIÁRIO: só a chave. Você NÃO envia nome nem documento — nós resolvemos no diretório Bre-B.
      bank_account_number: "@llaveDeTuUsuario",
    }),
  });
}

// 5) CONSULTE — não espere resposta imediata. Após o PUT, a transação
//    pode levar até ~30 s para avançar: nosso motor trabalha em ciclos.
while (["incomplete", "pending_customer_info_update"].includes((t = await tx()).status)) await sleep(5000);
// Quando chegar a pending_user_transfer_start você já tem destino e memo.
// t.withdraw_anchor_account · t.withdraw_memo (memo_type "id") · t.amount_out = COP líquidos
// t.fee_details.total vem em USDC: é a mesma taxa que a cotação deu em COP, em outra unidade
// t.message = o beneficiário resolvido: mostre ao usuário ANTES de assinar

// 6) Envie o USDC para essa conta com ESSE memo e continue consultando até completed.
Consulte, não presuma. Nenhuma dessas chamadas muda o status na hora: nosso motor revisa as transações em ciclos, então após enviar os dados do cliente a transação pode levar até uns 30 segundos para avançar. Se seu app concluir que falhou porque o status não mudou na hora, você vai mostrar um erro a alguém cujo saque está indo perfeitamente.

Os status que você verá

StatusO que significa e o que fazer
incompleteSAQUE: recém-criada; estamos calculando e verificando, avança no próximo ciclo, até ~30 s. DEPÓSITO: fica AQUI, e está certo — esperamos que seu usuário pague pelo link. Não espere que avance sozinha.
pending_customer_info_updateFaltam dados do cliente. Consulte GET /sep12/customer com este transaction_id, mostre os campos ao seu usuário e envie com PUT. O campo message da transação diz o que falta.
pending_user_transfer_startTudo pronto. Envie o USDC para withdraw_anchor_account com withdraw_memo. Antes de assinar, mostre o beneficiário que vem em message.
pending_anchor · pending_externalRecebemos seu USDC e o pagamento em pesos está em andamento. Apenas aguarde.
completedO beneficiário recebeu os pesos.
errorNão foi possível continuar e message diz o porquê. Se você já tinha enviado o USDC, a devolução é automática e integral.

O depósito

Há duas formas de iniciar um depósito, e não travam a mesma coisa:

Endpointamount vai emO que fica travadoQuando usar
GET /sep6/depositUSDCNada. É uma intenção: o formulário abre com o valor editável, seu usuário digita os pesos que vai pagar e liquida-se à taxa do momento.Quando não precisa prometer um número ao seu usuário. Atenção: amount=5000 aqui são cinco mil dólares.
GET /sep6/deposit-exchange + quote_idCOPValor e taxa. O formulário abre com ambos travados, e o que foi prometido é o que chega.Quando você garante a taxa ao seu usuário. É a do código abaixo.

As duas devolvem o mesmo, e é o que mais confunde: só um id e uma frase fixa dizendo para olhar a transação. O link não vem ali. Está na transação, no campo more_info_url, já assinado. Você o abre em um webview, seu usuário escolhe o banco e paga via PSE, e quando o pagamento é confirmado o USDC chega à conta Stellar e a transação passa a completed. Mínimo recomendado: 2.000 COP, porque a taxa do depósito é 1.785 e é descontada antes de converter.

TypeScript
// 1) Cotação firme (opcional, mas é o que garante a taxa ao seu usuário)
// USDC_ISSUER: o emissor que você leu do stellar.toml do ambiente (seção 3). Nunca fixo no código.
const q = await fetch(`${ANCHOR}/sep38/quote`, {
  method: "POST",
  headers: { ...auth, "Content-Type": "application/json" },
  body: JSON.stringify({
    sell_asset: "iso4217:COP", buy_asset: `stellar:USDC:${USDC_ISSUER}`,
    sell_amount: "5000", sell_delivery_method: "bank_transfer",
    country_code: "CO", context: "sep6",
  }),
}).then((r) => r.json());
// q.price · q.buy_amount · q.fee.total  ← a comissão vem À PARTE, não dentro do preço

// 2) Inicie o depósito com essa cotação.
const { id } = await fetch(
  `${ANCHOR}/sep6/deposit-exchange?amount=5000&destination_asset=USDC` +
  `&source_asset=iso4217:COP&quote_id=${q.id}&account=${account}&type=bank_transfer`,
  { headers: auth },
).then((r) => r.json());
// ATENÇÃO: esta resposta NÃO traz o link. Apenas { how, id }.

// 3) O link está na TRANSAÇÃO.
const t = await fetch(`${ANCHOR}/sep6/transaction?id=${id}`, { headers: auth })
  .then((r) => r.json()).then((r) => r.transaction);
// t.more_info_url            → abra em um webview. Seu token vive 10 min; se vencer, releia e sai outro.
// t.user_action_required_by  → até quando seu usuário tem. HOJE vem null: use o expires_at da cotação

// 4) Seu usuário escolhe o banco e paga via PSE. Continue sondando até completed.

Depois do link: o que acontece e o que você vê

Seu app abriu o more_info_url em um webview e continua sondando GET /sep6/transaction. Isto é o que seu usuário faz em cada momento e o estado que sua sondagem verá enquanto isso.

MomentoEstado que sua sondagem vêO que está acontecendo
Abre o linkincompleteVê o valor travado, a taxa congelada, a comissão e o IVA separados e o líquido em USDC, com o contador real. Preenche seus dados, autoriza o KYC (roda sobre o documento que digita), escolhe o banco e clica em Continuar.
Enviou o formuláriopending_user_transfer_startCriamos a ordem e a cotação foi consumida: aqui termina o prazo de 10 minutos. Enviamos ao portal do banco (PSE). Esse pagamento pode demorar o quanto for.
O banco confirmoupending_anchorRecebemos os pesos e estamos enviando o USDC para a conta Stellar.
Prontocompletedstellar_transaction_id traz o hash e message diz «USDC enviado on-chain». Seu usuário vê «Pago confirmado» com esse mesmo hash. Mostre a ele.
AbandonouincompleteFica ali, não expira sozinha. Se quiser pagar depois, inicie outro depósito: o link e a cotação já venceram.

Preço travado antes de mover o dinheiro

Cada operação do SEP-6 tem duas versões: a normal e a -exchange. A diferença é uma só coisa, se a taxa está fechada antes de mover o dinheiro ou não:

Sem cotaçãoCom cotação firme
Endpoints/sep6/deposit · /sep6/withdrawPrimeiro POST /sep38/quote, que devolve um quote_id. Depois /sep6/deposit-exchange ou /sep6/withdraw-exchange com esse quote_id.
A taxaA do momento da liquidação. Pode mudar entre pedir a operação e completá-la.A da cotação, congelada para essa transação. Uso único, não serve para outra.
O que você pode prometer ao seu usuárioNada exato. Ele vê o número no final.O número exato antes de confirmar: a cotação traz o preço e a comissão separados, e o prometido é o que chega.
Quando usarQuando seu app não mostra um valor antes de operar.Quando seu app diz «você vai receber X» antes de pagar ou enviar. É o que qualquer app séria faz.
Quanto duraNão se aplica.10 minutos no depósito, porque a pessoa abre o link, se verifica e escolhe o banco. 5 minutos no saque, que é programático.

O que precisa acontecer dentro do prazo: no depósito, seu usuário enviar o formulário; o pagamento via PSE pode demorar mais. No saque, você enviar a chave e os dados via SEP-12; nosso motor consome a cotação ao criar a ordem.

Como testar

Com os dados de teste da seção 7, contra o sandbox. Duas coisas que vale conferir lá, porque são as que surpreendem em produção: faça DOIS saques seguidos e confirme que no segundo pedimos a chave de novo, e faça um de 1,11 USDC para ver a devolução automática. Se testar o DEPÓSITO com a Demo Wallet do SDF, saiba que essa ferramenta recebe o more_info_url e não o mostra: só registra o estado da transação. Pegue nos logs dela o token do POST /auth e o id do depósito, chame GET /sep6/transaction?id=… com esse token, e o link está ali. Ao pagar, a Demo Wallet detecta o completed e fecha sozinha.

bash
# SEP-6 · depósito — NÃO precisa de SEP-12: a identidade é verificada no formulário do more_info_url
GET /sep6/deposit?asset_code=USDC&account=G...&amount=2&type=bank_transfer
#   → pague pelo more_info_url da transação (mesmo formulário e mesmo PSE de teste)

# SEP-6 · saque — PRECISA de SEP-12: PUT /sep12/customer (Authorization: Bearer <JWT SEP-10>)
{
  "account": "G...SUA_CONTA_TESTNET",
  "type": "sep6-withdrawal",
  "first_name": "Tester",                     # quem saca: seu usuário
  "last_name": "Sandbox",
  "email_address": "tester@example.com",
  "id_type": "CC",
  "id_number": "1000000001",
  "bank_account_number": "@alphamunKey01"     # o beneficiário: só a chave Bre-B
}
GET /sep6/withdraw?asset_code=USDC&account=G...&amount=1&type=breb   # amount=1.11 → com devolução

6 · Não gerencia chaves Stellar? Contas custodiais

Se seu produto não é uma wallet Stellar, a VANK também pode criar e custodiar uma conta Stellar para cada usuário seu: você a referencia com seu próprio identificador e nunca toca em chaves privadas — a VANK as gerencia com segurança. É o caminho rápido para fintechs que querem oferecer USDC sem operar infraestrutura cripto.

O acesso à integração custodial segue o mesmo processo de solicitação e certificação deste guia — escreva para nós e compartilharemos a documentação técnica específica.

7 · Certificação e ida à produção

A certificação não é um trâmite que você espera: você a faz hoje, no sandbox aberto. São três casos, e cada um mostra que sua integração lida bem com um momento diferente. Aqui está o que testar e, sobretudo, o que vamos olhar — para você saber se vai passar antes de nos enviar.

CasoO que provaO que verificamos
1 · Um depósitoQue você leva o usuário a pagar e credita o USDC na conta dele.Que o USDC chegou à conta que você declarou, e que seu app mostrou o valor em pesos antes de a pessoa pagar.
2 · Um saqueQue você pede o destino, envia o USDC ao lugar certo e acompanha a operação até o fim.Que você mostrou ao usuário o beneficiário resolvido ANTES de assinar, e que o líquido exibido coincide com o que pagamos.
3 · Um saque com devoluçãoQue você lida com o caso em que o pagamento falha. Saque exatamente 1,11 USDC: o sandbox rejeita de propósito.Que você reagiu ao status error, explicou ao usuário com nossa mensagem e refletiu o USDC devolvido em vez de dá-lo por perdido.
Quando os tiver, envie os três transaction IDs para contacto@vank.co. Revisamos cada um conforme o acima e respondemos com o que encontramos: se algo falhar, dizemos exatamente o quê, não uma recusa genérica.

Depois: ir para produção

  1. Crie sua conta VANK (app.vank.co) e escreva para contacto@vank.co com o domínio do seu app, o que você constrói e seu caso de uso.
  2. Requisito para conectar: seu domínio deve publicar o arquivo público https://tu-dominio/.well-known/stellar.toml com a SIGNING_KEY do seu app, e sua autenticação SEP-10 deve enviar esse clientDomain (co-assinando o challenge — o Wallet SDK suporta). É o padrão do ecossistema e é o que nos permite atribuir suas transações a você.
  3. Registramos seu domínio, assinamos o acordo de integração e você entra na mainnet com o USDC da Circle.

Dados de teste do sandbox

Tudo o que você precisa para concluir a certificação sem esperar por nós. São dados fictícios e compartilhados: não há nenhuma pessoa nem dinheiro real por trás, e você não deve usar documentos reais no sandbox.

O quêValorObservação
Ambientedev-stable-anchor.thisisvank.comStellar testnet. Use sua própria wallet na testnet (ou a Demo Wallet da SDF).
Fundos de testnetXLM: Friendbot · USDC: trustline ao emissor do stellar.toml e peça em https://faucet.circle.com (rede Stellar testnet)Primeiro a trustline, depois o faucet da Circle: sem trustline o USDC não entra. Seu próprio depósito de teste também deixa USDC.
Identidade para o KYCTester Sandbox · CC 1000000001Identidade fictícia com verificação instantânea. E-mail e telefone: qualquer um.
Depósito (PSE de teste)≥ 5.000 COP · banco BANCO UNION COLOMBIANO · o min_amount do /info é em USDCCom menos, a taxa fixa do sandbox consome o valor. Siga os passos do PSE de teste abaixo.
Saque (Bre-B de teste)chave @alphamunKey01 · ≥ 1 USDCTitular de teste do diretório Bre-B do sandbox. Vamos pedi-la a CADA saque: o destino nunca é herdado do anterior.
Saque com devoluçãomesma chave · exatamente 1.11 USDCEsse valor é rejeitado de propósito pelo sandbox: você verá a transação em error e o USDC de volta na sua conta, automaticamente.
Por API (SEP-6 / SEP-12)first_name=Tester last_name=Sandbox id_type=CC id_number=1000000001Para o saque, a chave Bre-B vai no campo bank_account_number.

Formulário de depósito, campo por campo (todos os campos com * são obrigatórios; digite exatamente isto):

CampoO que digitarObservação
Valor a depositar *5000Em COP. Menos que isso e a taxa fixa do sandbox consome tudo.
Nome completo *Tester Sandbox
Tipo de documento *CC · Cédula de CiudadaníaÉ a primeira opção da lista.
Número do documento *1000000001Só dígitos, sem pontos.
E-mail *tester@example.comQualquer um em formato de e-mail.
Telefone *3001234567Qualquer número.
Autorizo a verificação de identidade (KYC) *marque a caixaEm segundos aparece «Identidade verificada · KYC concluído».
Método de pagamento *PSE · banco BANCO UNION COLOMBIANOExatamente esse: a lista também traz «BANCO UNION» e «BANCO UNION COLOMBIANO FD2», que não servem para o teste.
Pagarclique no botãoLeva você à tela do PSE de teste (passos abaixo).

Tela do PSE de teste (o sandbox do gateway pede para confirmar o pagamento manualmente):

  1. No formulário escolha PSE e o banco BANCO UNION COLOMBIANO e continue para o pagamento.
  2. Na tela do PSE de teste clique em Debug.
  3. bankProcessDate: a mesma data que a tela mostra · transactionState: OK · authorizationID: 12.
  4. Clique em Call: deve responder Call Return: SUCCESS - TransactionState: OK.
  5. Clique em Return to PPE: você volta ao anchor e o USDC é creditado na sua wallet em poucos minutos.

Formulário de saque, campo por campo

CampoO que digitarObservação
Valor a sacar *1 USDC — ou 1.11 para o saque com devoluçãoVocê vê a taxa e a comissão antes de confirmar.
Seu nome completo (quem saca) *Tester SandboxÉ a identidade de quem saca, não a do beneficiário: a chave abaixo o identifica. Com uma wallet externa o formulário diz assim; pelo painel da VANK aparece como «Nome completo do titular».
Tipo de documento *CC · Cédula de CiudadaníaÉ a primeira opção da lista.
Número do documento *1000000001Só dígitos, sem pontos. É a identidade de teste com verificação preparada no sandbox.
E-mail *tester@example.comQualquer um em formato de e-mail.
Telefone *3001234567Qualquer número.
Autorizo a verificação de identidade (KYC) *marque a caixaRoda sobre o documento que você digitou. É a primeira verificação; a segunda é do beneficiário, e a chave cuida disso.
Como deseja receber seu dinheiro *Chave Bre-BA conta bancária aparece como «em breve»: não use.
Chave Bre-B do beneficiário *@alphamunKey01Só a chave. O formulário resolve o beneficiário de teste e o verifica sozinho: nome e documento NÃO são digitados. Os campos acima são da pessoa que saca, não dele.
Confirmarclique no botãoEnvie o USDC para a conta e o memo exibidos (sua wallet costuma fazer isso sozinha). Os pesos chegam em minutos; com 1.11 USDC você verá a rejeição e o USDC de volta.

Por API (SEP-6 / SEP-12) — os mesmos dados, com os nomes de campo do padrão:

bash
# SEP-6 · depósito — NÃO precisa de SEP-12: a identidade é verificada no formulário do more_info_url
GET /sep6/deposit?asset_code=USDC&account=G...&amount=2&type=bank_transfer
#   → pague pelo more_info_url da transação (mesmo formulário e mesmo PSE de teste)

# SEP-6 · saque — PRECISA de SEP-12: PUT /sep12/customer (Authorization: Bearer <JWT SEP-10>)
{
  "account": "G...SUA_CONTA_TESTNET",
  "type": "sep6-withdrawal",
  "first_name": "Tester",                     # quem saca: seu usuário
  "last_name": "Sandbox",
  "email_address": "tester@example.com",
  "id_type": "CC",
  "id_number": "1000000001",
  "bank_account_number": "@alphamunKey01"     # o beneficiário: só a chave Bre-B
}
GET /sep6/withdraw?asset_code=USDC&account=G...&amount=1&type=breb   # amount=1.11 → com devolução
Ao terminar, envie os 3 transaction IDs (depósito, saque e saque com devolução) para contacto@vank.co. Se algo no sandbox não se comportar como descrito aqui, escreva para o mesmo e-mail.

8 · Referência

ProtocolosSEP-10 (autenticação) · SEP-24 (com formulário) · SEP-6 (por API) · SEP-12 (dados do cliente) · SEP-38 (taxa firme)
AtivoUSDC na Stellar (emissor no stellar.toml de cada ambiente; Circle em produção)
Depósito mínimo5.000 COP
Saque mínimo1 USDC
Entrada fiatPSE (Colombia)
Saída fiatBre-B — pagamentos instantâneos para qualquer chave (Colômbia)
CotaçõesTaxa final mais a comissão declarada à parte, firme e de uso único (SEP-38). 10 min no depósito, 5 no saque
Suportecontacto@vank.co

9 · Métricas ao vivo (mainnet)

Cada número desta seção vem da rede: seu navegador lê os pagamentos em USDC da conta de tesouraria do anchor na rede pública da Stellar e os soma. Nenhum servidor da VANK participa. Um depósito é USDC que a tesouraria entrega a um usuário; um saque é USDC que ela recebe de um usuário.

Lendo a rede…

Os protocolos SEP são padrões abertos do ecossistema Stellar — a especificação completa está em stellar.org. VANK · Powered by Stellar.