Replace simple debug log with comprehensive logging of environment variables, including NODE_ENV, API key (masked), webhook secret, and base URL, to improve debugging and visibility in both development and production environments.
211 lines
5.6 KiB
TypeScript
211 lines
5.6 KiB
TypeScript
interface AbacatePayConfig {
|
|
apiKey: string;
|
|
baseUrl?: string;
|
|
}
|
|
|
|
interface CreateBillingParams {
|
|
amount: number;
|
|
metadata?: {
|
|
donorName?: string;
|
|
donorEmail?: string;
|
|
message?: string;
|
|
};
|
|
returnUrl?: string;
|
|
completionUrl?: string;
|
|
}
|
|
|
|
interface BillingResponse {
|
|
id: string;
|
|
amount: number;
|
|
status: "PENDING" | "PAID" | "EXPIRED" | "CANCELLED";
|
|
brCode?: string; // Código PIX copia-e-cola
|
|
brCodeBase64?: string; // QR Code em Base64
|
|
expiresAt?: string;
|
|
createdAt: string;
|
|
}
|
|
|
|
interface CreatePixParams {
|
|
amount: number; // em centavos
|
|
description: string;
|
|
expiresIn?: number; // em segundos, padrão 600 (10 min)
|
|
customer?: {
|
|
name: string;
|
|
email?: string;
|
|
cellphone?: string;
|
|
taxId?: string;
|
|
};
|
|
}
|
|
|
|
class AbacatePayClient {
|
|
private config: AbacatePayConfig;
|
|
|
|
constructor(config: AbacatePayConfig) {
|
|
this.config = {
|
|
...config,
|
|
baseUrl: config.baseUrl || "https://api.abacatepay.com/v1",
|
|
};
|
|
}
|
|
|
|
async createPixQrCode(params: CreatePixParams): Promise<BillingResponse> {
|
|
const requestBody: any = {
|
|
amount: params.amount,
|
|
expiresIn: params.expiresIn || 600, // 10 minutos por padrão
|
|
description: params.description,
|
|
};
|
|
|
|
if (params.customer) {
|
|
requestBody.customer = params.customer;
|
|
}
|
|
|
|
console.log("🔍 PIX Request:", JSON.stringify(requestBody, null, 2));
|
|
|
|
const response = await fetch(`${this.config.baseUrl}/pixQrCode/create`, {
|
|
method: "POST",
|
|
headers: {
|
|
Authorization: `Bearer ${this.config.apiKey}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(requestBody),
|
|
});
|
|
|
|
console.log("🔍 PIX Response Status:", response.status);
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
console.error("🔍 PIX Error:", errorData);
|
|
throw new Error(`Failed to create PIX: ${JSON.stringify(errorData)}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
console.log("🔍 PIX Success:", result);
|
|
|
|
if (result.error) {
|
|
throw new Error(result.error);
|
|
}
|
|
|
|
return result.data;
|
|
}
|
|
|
|
async createBilling(params: CreateBillingParams): Promise<BillingResponse> {
|
|
const response = await fetch(`${this.config.baseUrl}/billing`, {
|
|
method: "POST",
|
|
headers: {
|
|
Authorization: `Bearer ${this.config.apiKey}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
amount: params.amount * 100, // centavos
|
|
metadata: params.metadata,
|
|
return_url: params.returnUrl,
|
|
completion_url: params.completionUrl,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(
|
|
`Failed to create billing: ${errorData.message || response.statusText}`
|
|
);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
async getBillingStatus(billingId: string): Promise<BillingResponse> {
|
|
const response = await fetch(
|
|
`${this.config.baseUrl}/billing/${billingId}`,
|
|
{
|
|
headers: {
|
|
Authorization: `Bearer ${this.config.apiKey}`,
|
|
},
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(
|
|
`Failed to get billing status: ${
|
|
errorData.message || response.statusText
|
|
}`
|
|
);
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
// AbacatePay retorna { error: null, data: { ... } }
|
|
if (result.error) {
|
|
throw new Error(result.error);
|
|
}
|
|
|
|
// Retornar apenas o data
|
|
return result.data;
|
|
}
|
|
|
|
async getPixStatus(pixId: string): Promise<BillingResponse> {
|
|
// AbacatePay usa o endpoint /billing/{id} para todos os tipos de billing
|
|
const response = await fetch(`${this.config.baseUrl}/billing/${pixId}`, {
|
|
headers: {
|
|
Authorization: `Bearer ${this.config.apiKey}`,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
throw new Error(
|
|
`Failed to get PIX status: ${errorData.message || response.statusText}`
|
|
);
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.error) {
|
|
throw new Error(result.error);
|
|
}
|
|
|
|
return result.data;
|
|
}
|
|
|
|
verifyWebhookSignature(payload: string, signature: string): boolean {
|
|
// Método mantido para compatibilidade, mas validação agora é feita via query param
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Instância do cliente (será configurada com variáveis de ambiente)
|
|
const isProduction = process.env.NODE_ENV === "production";
|
|
const apiKey = isProduction
|
|
? process.env.ABACATE_APIKEY || "demo_key"
|
|
: process.env.ABACATE_TEST_APIKEY || "demo_key";
|
|
|
|
// Log completo das variáveis de ambiente configuradas
|
|
console.log("\n🔧 ==========================================");
|
|
console.log("🔧 VARIÁVEIS DE AMBIENTE DO ABACATEPAY");
|
|
console.log("🔧 ==========================================");
|
|
console.log(`📊 NODE_ENV: ${process.env.NODE_ENV || "não definido"}`);
|
|
console.log(`📊 Environment: ${isProduction ? "PRODUCTION" : "TEST"}`);
|
|
console.log(
|
|
`📊 API Key: ${apiKey ? "✅ Configurada (masqueada)" : "❌ NÃO CONFIGURADA"}`
|
|
);
|
|
console.log(
|
|
`📊 API Key preview: ${
|
|
apiKey ? apiKey.substring(0, 10) + "..." : "não definida"
|
|
}`
|
|
);
|
|
console.log(
|
|
`📊 Webhook Secret: ${
|
|
process.env.ABACATEPAY_WEBHOOK_SECRET
|
|
? "✅ Configurada"
|
|
: "❌ NÃO CONFIGURADA"
|
|
}`
|
|
);
|
|
console.log(
|
|
`📊 Base URL: ${process.env.NEXT_PUBLIC_BASE_URL || "não definido"}`
|
|
);
|
|
console.log("🔧 ==========================================\n");
|
|
|
|
export const abacatePay = new AbacatePayClient({
|
|
apiKey,
|
|
});
|
|
|
|
export type { CreateBillingParams, BillingResponse };
|