Receitas

Investigue um pagamento com falha

Uma ferramenta de suporte somente leitura: entra o ID de um pagamento, sai a causa da falha.

Crie uma ferramenta de suporte que recebe o ID de um pagamento e responde "por que este pagamento falhou?" a partir da sua API de pagamentos e da sua página de status. O agente só pode ler: ele não consegue estornar, tentar de novo nem alterar nada. A configuração leva cerca de quinze minutos.

Uma execução como esta costuma levar de 10 a 15 segundos. A maior parte do custo é a computação, cobrada a $0.0002 por segundo, e cada página que o agente busca custa $0.001. A parte do modelo depende do modelo que você escolher; por isso, leia cost_micros nas suas primeiras execuções. O orçamento de $0.50 é um teto, não um preço.

  1. Reúna o que você precisa

    • Uma conta do Ephemeral com créditos e duas chaves de API em Chaves de API: uma chave de membro para o seu backend, que inicia as execuções, e uma chave de administrador para a configuração única da conexão. Veja funções e chaves.
    • A URL base da sua API de pagamentos (HTTPS, acessível pela internet) e uma chave somente leitura para ela, como uma chave restrita que só pode ler pagamentos.
    • Uma página de status pública em um único domínio, aqui status.example.com.
    • Um endpoint HTTPS no seu servidor que receberá o resultado.
    Terminal
    export EPHEMERAL_URL=https://app.ephemer.al
    export EPHEMERAL_API_KEY=eak_…          # member key, for your backend
    export EPHEMERAL_ADMIN_KEY=eak_…        # admin key, for setup only
    export EPHEMERAL_CALLBACK_SECRET=$(openssl rand -hex 16)   # 32 characters; keep it on your server
  2. Escreva e envie o playbook

    O playbook é onde fica o conhecimento da sua equipe: quais chamadas fazer e como ler a resposta. Mantenha-o curto e concreto. O agente o recebe como um arquivo somente leitura junto com a tarefa.

    playbook.md
    # Failed payment playbook
    
    You can only read. The payments connection allows GET, and web access is limited to status.example.com.
    
    1. GET /payments/{payment_id}. Note status, amount, currency, failure_code and failure_message.
    2. GET /payments/{payment_id}/attempts. Check whether earlier attempts failed for the same reason.
    3. If failure_code is processor_error or timeout, read https://status.example.com for incidents around that time.
    4. Decide the cause:
       - card_declined, insufficient_funds, expired_card: the customer's bank or card. Suggest a retry or another card.
       - processor_error, timeout: ours or the processor's. Say whether the status page shows an incident.
       - fraud_review: a risk rule held it. Do not suggest bypassing it.
    5. Never guess. If a call fails or a field is missing, say so.
    
    Answer in at most six lines: the cause, the evidence (field and value) and the next step for the support agent.
    Do not include card numbers or customer email addresses.
    curl $EPHEMERAL_URL/v1/files \
      -H "Authorization: Bearer $EPHEMERAL_API_KEY" \
      -F [email protected]

    O arquivo é armazenado com o nome playbook.md. Enviá-lo de novo adiciona uma nova versão, e os fluxos de trabalho que citam o arquivo usam a versão mais recente quando uma execução começa. Veja arquivos.

  3. Crie a conexão payments-api

    Uma conexão guarda o endereço e a chave da API dentro do Ephemeral. O agente a chama pelo nome e nunca vê a chave. Defina allowed_methods como ["GET"] para que todos os outros métodos sejam recusados.

    curl -X PUT $EPHEMERAL_URL/v1/connections/payments-api \
      -H "Authorization: Bearer $EPHEMERAL_ADMIN_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "type": "http",
        "url": "https://api.example.com/v1",
        "auth": { "type": "bearer", "token": "rk_live_…" },
        "allowed_methods": ["GET"],
        "instructions": "Look up a payment with GET /payments/{id} and its attempts with GET /payments/{id}/attempts. Amounts are in cents."
      }'

    Prefere o dashboard? Abra Conexões, escolha Adicionar conexão e API HTTP, informe o nome payments-api e a URL base, selecione Token Bearer e cole a chave; depois marque apenas GET em Métodos HTTP permitidos. As instructions dizem ao agente quais endpoints existem; ele as enxerga, então mantenha segredos fora delas.

    Ao ler a conexão de volta, nenhum token aparece, e GET /v1/catalog/connections a lista para os membros com o tipo e os métodos permitidos, sem a URL nem qualquer credencial.

  4. Salve o fluxo de trabalho

    Um fluxo de trabalho reúne a tarefa, o playbook, a conexão e os limites sob um único nome, e assim o seu backend só envia o ID do pagamento. O agente enxerga a conexão como payments. O acesso à web fica limitado à página de status, e o shell fica desligado porque a tarefa não precisa de comandos.

    curl -X PUT $EPHEMERAL_URL/v1/workflows/investigate-payment \
      -H "Authorization: Bearer $EPHEMERAL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "prompt": "Find out why this payment failed.",
        "files": [{ "file": "playbook.md" }],
        "connections": { "payments": { "ref": "payments-api", "allowed_methods": ["GET"] } },
        "web": { "allow": ["status.example.com"] },
        "shell": false,
        "timeout_seconds": 120
      }'

    Nenhum model é definido, então cada execução usa o modelo padrão no momento em que começa; escolha outro no catálogo de modelos se preferir. O ID do pagamento, o orçamento e o callback pertencem a cada execução, não ao fluxo de trabalho.

  5. Inicie uma execução a partir do seu backend

    Envie o nome do fluxo de trabalho, o ID do pagamento, o orçamento e um callback. O Idempotency-Key torna uma nova tentativa segura: uma chave repetida retorna a execução que já existe com 200 em vez de iniciar uma segunda. Use uma chave que você consiga reconstruir, como o ID do pagamento ou o ID do seu ticket.

    const paymentId = "pay_123";
    
    const response = await fetch(`${process.env.EPHEMERAL_URL}/v1/runs`, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.EPHEMERAL_API_KEY}`,
        "Content-Type": "application/json",
        "Idempotency-Key": `investigate-${paymentId}`,
      },
      body: JSON.stringify({
        workflow: "investigate-payment",
        input: { payment_id: paymentId },
        max_cost_micros: 500000,
        callback: {
          url: "https://example.com/hooks/ephemeral",
          secret: process.env.EPHEMERAL_CALLBACK_SECRET,
        },
      }),
    });
    const run = await response.json(); // { id: "run_…", status: "queued", … }

    A resposta é 202 Accepted com o objeto da execução, no status queued. A execução começa assim que um worker estiver livre. A URL do callback deve usar HTTPS e resolver para um endereço público, e o segredo deve ter de 24 a 1.024 caracteres; caso contrário, a requisição falha com 400 e nada é iniciado. No serviço hospedado, 402 significa que os seus créditos não cobrem o orçamento.

  6. Verifique o callback

    Quando a execução chega a um status final, o Ephemeral envia um único POST assinado com o objeto da execução. Confira a assinatura contra os bytes brutos do corpo antes de confiar em qualquer coisa nele. O texto assinado é o cabeçalho X-Ephemeral-Timestamp, um ponto e o corpo, assinados com HMAC-SHA256 usando o seu segredo. Veja callbacks para o esquema completo.

    Node.js, sem dependências
    import crypto from "node:crypto";
    import http from "node:http";
    
    const handled = new Set(); // use your database in production
    
    http
      .createServer((req, res) => {
        const chunks = [];
        req.on("data", (chunk) => chunks.push(chunk));
        req.on("end", () => {
          const body = Buffer.concat(chunks);
          const timestamp = req.headers["x-ephemeral-timestamp"] ?? "";
          const signature = req.headers["x-ephemeral-signature"] ?? "";
          const expected =
            "sha256=" +
            crypto
              .createHmac("sha256", process.env.EPHEMERAL_CALLBACK_SECRET)
              .update(timestamp + ".")
              .update(body)
              .digest("hex");
    
          const valid =
            signature.length === expected.length &&
            crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
          const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300;
          if (!valid || !fresh) return res.writeHead(401).end();
    
          const run = JSON.parse(body);
          if (!handled.has(run.id)) {
            handled.add(run.id);
            // Attach run.output to the support ticket for run.id here.
          }
          res.writeHead(204).end(); // any 2xx counts as delivered
        });
      })
      .listen(3000); // serve this behind HTTPS at /hooks/ephemeral

    Qualquer resposta que não seja 2xx é tentada de novo com intervalos crescentes, então a mesma execução pode chegar duas vezes. É por isso que o handler memoriza os IDs das execuções.

  7. Leia o resultado

    O corpo do callback é o objeto da execução. Para o pagamento de exemplo, ele fica assim:

    JSON
    {
      "id": "run_118622d16f00105f7bba6d2281774705",
      "status": "succeeded",
      "output": "- **Cause:** The customer’s bank declined the payment for insufficient funds.\n- **Evidence:** `failure_code: insufficient_funds`; `failure_message: The card issuer declined the charge: insufficient funds.`\n- **Attempts:** Both attempts failed for the same reason.\n- **Next step:** Suggest the customer retry after resolving the balance issue or use another card.",
      "created_at": "2026-10-03T09:14:05.118Z",
      "started_at": "2026-10-03T09:14:05.402Z",
      "finished_at": "2026-10-03T09:14:16.447Z",
      "max_cost_micros": 500000,
      "cost_micros": 2618,
      "billing_pending": false,
      "zero_data_retention": false
    }

    output é a resposta do agente em texto. cost_micros é o custo total em milionésimos de dólar, aqui $0.002618. Uma execução que não teve sucesso tem status failed, timed_out ou cancelled e um error no lugar de uma saída; mostre isso ao seu atendente em vez de nada. Se billing_pending for true, o custo ainda é provisório: leia a execução de novo com GET /v1/runs/{id} um pouco depois. Para ver cada chamada que o agente fez, abra a execução no dashboard ou acompanhe os seus eventos.

Por que é seguro

RiscoO que impede
O agente altera ou estorna um pagamento.A conexão e o fluxo de trabalho permitem apenas GET; qualquer outro método é recusado com HTTP method not permitted.
A chave de pagamentos vaza.A chave fica no Ephemeral. A microVM não tem rede nem chave; o broker adiciona a chave a cada requisição e remove as credenciais das respostas.
Os dados vão para um site desconhecido.O acesso à web permite apenas status.example.com, e os redirecionamentos são conferidos contra a mesma lista. Veja acesso à web.
O agente executa comandos.shell é false.
Uma execução custa mais do que o esperado.O orçamento de 500.000 micros ($0.50) é reservado no início e não pode ser excedido; timeout_seconds encerra a execução após 120 segundos.
Alguém forja o resultado.O seu endpoint aceita apenas requisições cuja assinatura é válida.
Dê à chave somente leitura apenas acesso de leitura
A conexão limita o que o agente pode chamar, mas uma chave que só pode ler é a garantia mais forte. Crie uma chave restrita no seu provedor de pagamentos exclusivamente para esta conexão, para poder revogá-la sozinha.
Ajustando o playbook
Execute-o em algumas falhas conhecidas e leia a saída. Quando estiver errada, altere o playbook e envie-o de novo; a próxima execução usa o novo arquivo. Veja fluxos de trabalho para saber como os campos salvos e as substituições por execução se combinam.
© 2026 EphemeralProduzido por erni.works
esc

Nada corresponde a “”.