# Primeiros Passos

Existem dois ambientes de integração: **Staging** e **Production**. Cada um possui características específicas:

#### Staging <a href="#staging" id="staging"></a>

Este ambiente é destinado ao desenvolvimento ou teste de funcionalidades.

#### Production <a href="#production" id="production"></a>

Este é o ambiente que os usuários terão acesso, qualquer ação realizada nele será permanente.

#### Endpoints <a href="#endpoints" id="endpoints"></a>

| Ambiente   | URI                                        |
| ---------- | ------------------------------------------ |
| Staging    | <https://staging-api.altpaybr.com.br/api/> |
| Production | <https://api.altpaybr.com.br/api/>         |

### Exemplo de Uso <a href="#exemplo-de-uso" id="exemplo-de-uso"></a>

Este é um exemplo completo de como se conectar com a nossa API através da biblioteca axios do NodeJS, este formato foi pensado para evitar repetição de lógica, com a implementaçao de um mecanismo automático que:

* Obtém o token quando necessário
* Anexa o token em todas as requisições
* Detecta expiração de sessão
* Reautentica automaticamente
* Reexecuta requisições que falharam por expiração

#### Controle de Concorrência

Para evitar múltiplas autenticações simultâneas em cenários concorrentes:

* Um estado interno (`isRefreshing`) indica se já existe uma renovação em andamento
* Requisições que falharem durante esse período são adicionadas a uma fila (`pendingRequests`)
* Após a renovação, todas as requisições pendentes são reexecutadas com o novo token

Esse mecanismo evita chamadas redundantes ao endpoint de autenticação e garante consistência no uso do token.

#### Prevenção de Loop Infinito

Cada requisição possui uma flag interna (`_retry`) que impede que o processo de reautenticação seja executado mais de uma vez para a mesma chamada.

Isso evita loops infinitos em casos de falha persistente na autenticação.

{% tabs %}
{% tab title="altpay.ts" %}

```typescript
import axios, { AxiosError } from "axios";

interface AltpayErrorBody {
  id: string; // ID da requisição que o erro foi gerado (Nos envie em caso de erro interno)
  code: string; // Código interno do erro na AltPay (Veja a documentação de erros)
  message: string; // Sempre é retornada, e, contem uma explicação do erro
  status_code: number; // Status code retornado pela API
  timestamp: string; // Momento em que o erro ocorreu na AltPay
  path: string; // Rota chamada que causou o erro
  handled: boolean; // Caso o erro tenha sido tratado pela AltPay
  errors: string[]; // Quando o erro possui multiplas mensagens (Use no lugar do message)
}

const altpayApi = axios.create({
  baseURL: process.env.ALTPAY_API_URL,
});

let altpayAccessToken: string | null = null;
let isRefreshing = false;
let pendingRequests: Array<{
  resolve: (token: string | null) => void;
  reject: (err: any) => void;
}> = [];

// Interceptor de requisição:
// Garante que todas as chamadas saiam com um access_token válido
altpayApi.interceptors.request.use(async (config) => {
  if (!altpayAccessToken) {
    await authenticate();
  }

  if (altpayAccessToken) {
    config.headers = config.headers ?? {};
    config.headers.Authorization = `Bearer ${altpayAccessToken}`;
  }

  return config;
});

// Interceptor de resposta:
// Trata expiração de sessão e reexecuta a requisição original
altpayApi.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    const errorCode = error?.response?.data?.code;

    // Verifica se o erro é de sessão expirada
    if (errorCode === "SESSION_EXPIRED") {
      // Evita loop infinito caso a revalidação falhe
      if (originalRequest._retry) {
        return Promise.reject(error);
      }

      originalRequest._retry = true;

      // Caso já exista um processo de renovação em andamento,
      // adiciona a requisição na fila para ser executada depois
      if (isRefreshing) {
        return new Promise((resolve, reject) => {
          pendingRequests.push({ resolve, reject });
        }).then((token) => {
          originalRequest.headers.Authorization = `Bearer ${token}`;
          return altpayApi(originalRequest);
        });
      }

      isRefreshing = true;

      try {
        // Reautentica e obtém novo token
        await authenticate();

        // Libera todas as requisições pendentes
        pendingRequests.forEach((p) => p.resolve(altpayAccessToken));
        pendingRequests = [];

        // Reexecuta a requisição original com o novo token
        originalRequest.headers.Authorization = `Bearer ${altpayAccessToken}`;
        return altpayApi(originalRequest);
      } catch (err) {
        // Propaga erro para todas as requisições pendentes
        pendingRequests.forEach((p) => p.reject(err));
        pendingRequests = [];

        return Promise.reject(err);
      } finally {
        isRefreshing = false;
      }
    }

    return Promise.reject(error);
  }
);

// Pega apenas a body dos erros da AltPay
function getErrorResponseBody(error: unknown): AltpayErrorBody {
  if (error instanceof AxiosError) {
    const body = error.response?.data;

    if (body) {
      return body as AltpayErrorBody;
    }
  }

  throw error;
}

// Função responsável por obter um novo access_token
// Utiliza uma instância isolada do axios para evitar interceptors
async function authenticate() {
  const { data } = await axios.post(
    `${process.env.ALTPAY_API_URL}/v1/auth/token`,
    {
      client_id: process.env.ALTPAY_CLIENT_ID,
      client_secret: process.env.ALTPAY_CLIENT_SECRET,
    }
  );

  altpayAccessToken = data.access_token;
}

// Exemplo de consumo de endpoint protegido
export async function getCustomers() {
  try {
    const { data } = await altpayApi.get("/v1/customers");
    
    return data;
  } catch (error) {
    const body = getErrorResponseBody(error);

    const message = body.errors?.length
      ? body.errors.join(";\n")
      : body.message;

    console.error(`[AltPay Error] ${body.code}: ${message}`);

    throw error;
  }
}
```

{% endtab %}

{% tab title=".env" %}

```bash
ALTPAY_API_URL="https://staging-api.altpaybr.com.br/api"
ALTPAY_CLIENT_ID="67ed57d...e30ed9"
ALTPAY_CLIENT_SECRET="alt_cs_fd321a1d...7cbaf4"
```

* **ALTPAY\_API\_URL** → URL base da nossa API (staging ou produção)
* **ALTPAY\_CLIENT\_ID** → Seu identificador público da API
* **ALTPAY\_CLIENT\_SECRET** → Sua chave screta de acesso a API (mantenha secreto)
  {% endtab %}
  {% endtabs %}

Nosso objetivo é que você consiga sair do zero até uma integração funcional no menor tempo possível, com confiança e clareza em cada etapa do processo, por isso pedimos que leia atentamente cada etapa descrita em nossa documentação.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.altpaybr.com.br/documentation/api-integration/quickstart.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
