Encountering "absolute URLs needed" error in Zapier while integrating GoCardless with LexOffice

I’m trying to set up a workflow in Zapier that links my GoCardless payments to LexOffice for invoicing. Despite ensuring that my URLs begin with ‘https’, I am still facing an error message indicating that “absolute URLs needed”. As I’m relatively new to this, I would greatly welcome any assistance or advice.

Here’s the JavaScript code that I’ve been working with:

// Configuration settings
const isTestMode = true; // Set to false for production invoices

// API Configuration
const paymentReference = inputData["paymentRef"] || inputData["Payment Event Link"];
const gcApiKey = inputData["gcToken"];
const gcBaseUrl = inputData["gcApiUrl"];
const paymentState = inputData["paymentState"];
const lexApiKey = inputData["lexToken"];
const lexBaseUrl = inputData["lexApiUrl"];

if (!paymentReference) {
  throw new Error("Missing payment reference ID");
}

const refList = paymentReference.split(',');
const invoiceResults = [];
const processingLogs = [];

// Process each payment reference
for (const ref of refList) {
  try {
    console.log(`Processing payment: ${ref}`);
    
    const paymentInfo = await fetchPaymentDetails(
      gcBaseUrl,
      gcApiKey,
      ref,
      paymentState
    );
    
    invoiceResults.push(paymentInfo);
  } catch (err) {
    console.error(`Failed to process ${ref}: ${err.message}`);
    processingLogs.push({ error: err.message, reference: ref });
  }
}

// Create invoices in LexOffice
for (const invoice of invoiceResults) {
  try {
    console.log(`Creating invoice:`, invoice);
    const result = await generateInvoice(lexBaseUrl, lexApiKey, invoice, isTestMode);
    processingLogs.push(result);
  } catch (err) {
    console.error(`Invoice creation failed: ${err.message}`);
    processingLogs.push({ error: err.message });
  }
}

return { results: processingLogs };

// Helper functions
function getHeaders() {
  return {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  };
}

async function fetchPaymentDetails(baseUrl, apiKey, refId, expectedStatus) {
  if (!refId) {
    throw new Error("Reference ID missing");
  }
  
  const requestUrl = `${baseUrl}/payments/${refId}`;
  
  const config = {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'GoCardless-Version': '2015-07-06',
      ...getHeaders()
    }
  };
  
  const apiResponse = await fetch(requestUrl, config);
  const data = await apiResponse.json();
  
  console.log(`Payment data for ${refId}:`, JSON.stringify(data, null, 2));
  
  if (!data.payments) {
    throw new Error(`Invalid response format: ${JSON.stringify(data)}`);
  }
  
  const paymentData = data.payments;
  const currentStatus = paymentData.status;
  
  if (!currentStatus) {
    throw new Error(`Status undefined for payment: ${refId}`);
  }
  
  if (currentStatus.toLowerCase() !== expectedStatus.toLowerCase()) {
    throw new Error(`Status mismatch: got ${currentStatus}, expected ${expectedStatus}`);
  }
  
  return {
    creation_date: paymentData.created_at,
    billing_date: paymentData.charge_date,
    total: paymentData.amount / 100,
    client_id: paymentData.links.customer
  };
}

async function generateInvoice(baseUrl, apiKey, data, testMode = true) {
  const finalizeParam = testMode ? "" : '[?finalize=true]';
  const invoiceEndpoint = baseUrl + finalizeParam;
  
  const requestConfig = {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      ...getHeaders()
    }
  };
  
  const invoiceAmount = data.total;
  
  const invoicePayload = {
    "archived": false,
    "voucherDate": new Date().toISOString(),
    "lineItems": [
      {
        "type": "custom",
        "name": "Professional Services Ltd",
        "quantity": 1,
        "unitName": "Service €",
        "unitPrice": {
          "currency": "EUR",
          "netAmount": invoiceAmount,
          "grossAmount": invoiceAmount,
          "taxRatePercentage": 19
        }
      }
    ],
    "totalPrice": {
      "currency": "EUR"
    },
    "taxConditions": {
      "taxType": "gross"
    },
    "paymentConditions": {
      "paymentTermDuration": 14,
      "paymentTermLabel": "Payment due within 14 days"
    },
    "shippingConditions": {
      "shippingDate": new Date().toISOString(),
      "shippingType": "service"
    },
    "title": "Invoice",
    "introduction": "Thank you for your business",
    "remark": "We appreciate your prompt payment"
  };
  
  requestConfig.body = JSON.stringify(invoicePayload);
  
  const response = await fetch(invoiceEndpoint, requestConfig);
  return await response.json();
}

This error keeps persisting even with the URLs being formatted as ‘https’. I’m eagerly looking forward to any insights or solutions.

This usually happens because of how Zapier builds URLs in the finalize parameter section. Your code has a bug on this line: const finalizeParam = testMode ? "" : '[?finalize=true]'; - drop those brackets. It should be const finalizeParam = testMode ? "" : '?finalize=true';. Also make sure you’re joining it properly with baseUrl. I ran into the same thing and ended up using a regex to validate URLs before making requests - caught all the malformed ones. Add console.log(invoiceEndpoint) right before your fetch call so you can see if the full URL looks right.

Hey! I ran into this same problem. Double-check that your Zapier input fields for gcApiUrl and lexApiUrl have the complete https URLs. Zapier sometimes sends partial paths or relative URLs instead of the full ones you expect. Log those values first to see what’s actually getting passed through.

I’ve hit this exact problem before - it’s usually a URL construction issue that’s hard to spot. Zapier validates URLs when they actually run, not during setup, so things can break unexpectedly.

Your fetchPaymentDetails function looks right, but I’d add some validation before those fetch calls. Check if your URL starts with ‘https://’ and make sure no values are undefined. I had a setup where my baseUrl seemed perfect during testing but had trailing characters or encoding problems that only appeared during execution.

Try logging the actual URLs: add console.log('Final URL:', requestUrl) in fetchPaymentDetails and console.log('Invoice endpoint:', invoiceEndpoint) in generateInvoice. You’ll see exactly what’s being built. Sometimes Zapier’s input mapping sneaks in weird characters or whitespace that breaks the URL format.