Alegra devolvió 403 al registrar cobro (Collections)

hola tengo este problema con este codigo

foreach ($order->get_items() as $item) {
$product = $item->get_product();
$qty = max(1, (int)$item->get_quantity());
$name = $item->get_name();
$desc = $product ? substr(wp_strip_all_tags($product->get_description()), 0, 200) : ‘’;

        $split = $this->woo_alegra_lookup_split_for_name($name);
        if (is_array($split) && isset($split['servicio_psicologa'], $split['costo_legatus'], $split['comision_plataforma'])) {
            
            $alegra_item_id = $product ? (int)$product->get_meta('_alegra_item_id', true) : 0;
            if ($alegra_item_id) {
                $service_line = [
                    'id'       => $alegra_item_id,
                    'price'    => round((float)$split['servicio_psicologa'], 2),
                    'quantity' => $qty,
                ];
                $tax_id = $this->map_tax_for_order_item($item);
                if ($tax_id > 0) $service_line['tax'] = [['id' => (int)$tax_id]];
                $items[] = $service_line;
            }

            
            $platform_mgmt = [
                'id'       => 127,
                'price'    => round((float)$split['costo_legatus'], 2),
                'quantity' => $qty,
            ];
            $platform_tax_id = apply_filters('woo_alegra_platform_fee_tax_id', 0, $item, $order);
            if ((int)$platform_tax_id > 0) $platform_mgmt['tax'] = [['id' => (int)$platform_tax_id]];
            $items[] = $platform_mgmt;

            
            $platform_comm = [
                'id'       => 128,
                'price'    => round((float)$split['comision_plataforma'], 2),
                'quantity' => $qty,
            ];
            $commission_tax_id = apply_filters('woo_alegra_platform_commission_tax_id', 0, $item, $order);
            if ((int)$commission_tax_id > 0) $platform_comm['tax'] = [['id' => (int)$commission_tax_id]];
            $items[] = $platform_comm;
        } else {
            $unit_price = (float)$order->get_item_total($item, false, true);
            $line = [
                'name'        => $name,
                'description' => $desc,
                'price'       => round($unit_price, 2),
                'quantity'    => $qty,
            ];
            $tax_id = $this->map_tax_for_order_item($item);
            if ($tax_id > 0) $line['tax'] = [['id' => (int)$tax_id]];
            $items[] = $line;
        }
    }

    
    if ((float)$order->get_shipping_total() > 0) {
        foreach ($order->get_items('shipping') as $ship) {
            $line = [
                'name'        => 'Envío',
                'description' => $ship->get_method_title(),
                'price'       => round((float)$order->get_shipping_total(), 2),
                'quantity'    => 1,
            ];
            $tax_id = $this->map_tax_for_shipping_item($ship);
            if ($tax_id > 0) $line['tax'] = [['id' => (int)$tax_id]];
            $items[] = $line;
            break;
        }
    }

    $date_created = $order->get_date_created();
    $date_str     = $date_created ? $date_created->date('Y-m-d') : current_time('Y-m-d');

    
    
    
    if ($test_mode) {
        $company = trim((string)$order->get_billing_company());
        $full    = trim(trim((string)$order->get_billing_first_name()).' '.trim((string)$order->get_billing_last_name()));
        $email   = trim((string)$order->get_billing_email());
        list($doc, $identType) = $this->woo_alegra_get_order_document_and_type($order);

        $invoice_data = [
            'client' => [
                'id'                 => 'DRYRUN',
                'name'               => $company ?: ($full ?: ($email ?: ('Cliente Woo '.$order->get_id()))),
                'email'              => $email ?: null,
                'identification'     => $doc ?: null,
                'identificationType' => $doc ? ($identType ?: 'CC') : null,
            ],
            'date'         => $date_str,
            'dueDate'      => $date_str,
            'items'        => $items,
            'observations' => 'Pedido WooCommerce #'.$order->get_order_number(),
            'status'       => 'open',
        ];
        if (!empty($opts['number_template_id'])) {
            $invoice_data['numberTemplate'] = ['id'=>(string)$opts['number_template_id']];
        }

        $order->update_meta_data('_alegra_payload_dryrun', wp_json_encode($invoice_data, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
        $order->save();
        $order->add_order_note('Alegra (dry-run): payload generado y NO enviado.');
        return;
    }

    
    
    
    try {
        $api_client = $this->get_api_client();

        
        $order->add_order_note('🔄 Paso 1: Creando/actualizando contacto en Alegra...');
        $client_id = $api_client->create_or_update_client($order);
        if (empty($client_id)) throw new Exception('No se pudo obtener un ID de cliente válido');
        $order->add_order_note('✅ Paso 1: Cliente ID = ' . $client_id);

        
        $order->add_order_note('🔄 Paso 2: Normalizando contacto (identificación/nombre/tipo)...');
        try {
            $this->ensure_contact_identification_ready($client_id, $order);
            $order->add_order_note('✅ Paso 2: Contacto normalizado.');
        } catch (\Throwable $t) {
            $order->add_order_note('⚠️ Paso 2: No se pudo normalizar contacto: '.$t->getMessage());
        }

        
        $order->add_order_note('🔄 Paso 3: Leyendo datos actualizados del contacto...');
        $contact = $api_client->get_contact($client_id);
        $this->log('Contacto leído de Alegra: ' . wp_json_encode($contact, JSON_PRETTY_PRINT), 'info');
        $order->update_meta_data('_alegra_contact_snapshot', wp_json_encode($contact, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
        $order->save();
        $order->add_order_note('✅ Paso 3: Contacto leído. Ver meta _alegra_contact_snapshot');

        
        $order->add_order_note('🔄 Paso 4: Construyendo payload del cliente para factura...');
        try {
            $client_payload = $this->build_client_payload_for_invoice($client_id, $order, $contact);

            list($doc_from_order, $doc_type_from_order) = $this->woo_alegra_get_order_document_and_type($order);
            $safe_name     = $this->woo_alegra_build_safe_name($order);
            $ident_number  = !empty($contact['identification']) ? (string)$contact['identification'] : (string)$doc_from_order;
            $ident_type    = !empty($contact['identificationObject']['type'])
                ? (string)$contact['identificationObject']['type']
                : (!empty($contact['identificationType']) ? (string)$contact['identificationType'] : ($doc_type_from_order ?: 'CC'));

            if (empty($client_payload) || !is_array($client_payload)) $client_payload = [];
            if (empty($client_payload['id']))                 $client_payload['id'] = (int)$client_id;
            if (empty($client_payload['name']))               $client_payload['name'] = $safe_name;
            if (empty($client_payload['identification']) && !empty($ident_number)) $client_payload['identification'] = $ident_number;
            if (empty($client_payload['identificationType']) && !empty($ident_type)) $client_payload['identificationType'] = $ident_type;

            $order->update_meta_data('_alegra_client_payload_built', wp_json_encode($client_payload, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
            $order->save();
            $order->add_order_note('✅ Paso 4: Client payload construido. Ver meta _alegra_client_payload_built');
        } catch (Exception $e) {
            $order->add_order_note('❌ Paso 4 FALLÓ: ' . $e->getMessage());
            throw $e;
        }

        
        $paymentForm   = $order->is_paid() ? 'CASH' : 'CREDIT';
        $gateway_id    = method_exists($order, 'get_payment_method') ? (string) $order->get_payment_method() : '';
        $gateway_id_lc = strtolower($gateway_id);
        $paymentMethod = 'CASH';

        switch (true) {
            case strpos($gateway_id_lc, 'wompi') !== false:
            case strpos($gateway_id_lc, 'payu') !== false:
            case strpos($gateway_id_lc, 'mercado') !== false:
            case strpos($gateway_id_lc, 'stripe') !== false:
            case strpos($gateway_id_lc, 'redsis') !== false:
            case strpos($gateway_id_lc, 'epayco') !== false:
            case strpos($gateway_id_lc, 'placetopay') !== false:
            case strpos($gateway_id_lc, 'woocommerce-payments') !== false:
                $paymentMethod = 'CREDIT_CARD';
                $paymentForm   = 'CASH';
                break;

            case strpos($gateway_id_lc, 'transfer') !== false:
            case strpos($gateway_id_lc, 'banc') !== false:
            case strpos($gateway_id_lc, 'pse') !== false:
                $paymentMethod = 'TRANSFER';
                $paymentForm   = 'CASH';
                break;

            case strpos($gateway_id_lc, 'contraentrega') !== false:
            case strpos($gateway_id_lc, 'cod') !== false:
            case strpos($gateway_id_lc, 'cash') !== false:
                $paymentMethod = 'CASH';
                $paymentForm   = 'CASH';
                break;

            default:
                if (!$order->is_paid()) { $paymentForm = 'CREDIT'; $paymentMethod = 'CASH'; }
                else { $paymentForm = 'CASH'; $paymentMethod = 'CASH'; }
        }
        $paymentForm   = apply_filters('woo_alegra_payment_form', $paymentForm, $order, $gateway_id);
        $paymentMethod = apply_filters('woo_alegra_payment_method', $paymentMethod, $order, $gateway_id);
        $order->add_order_note('🧾 Forma/medio de pago Alegra → paymentForm='.$paymentForm.' | paymentMethod='.$paymentMethod.' | gateway='.$gateway_id);

        
        $order->add_order_note('🔄 Paso 5: Construyendo payload completo de factura...');

        
        foreach ($items as &$it) { if (empty($it['unit'])) $it['unit'] = 'service'; }
        unset($it);
        $items = $this->ensure_alegra_items_active($items, $api_client, $order);

        
        $client_address = [];
        if (!empty($contact['address']) && is_array($contact['address'])) {
            $client_address = array_filter([
                'address'    => $contact['address']['address']    ?? null,
                'city'       => $contact['address']['city']       ?? null,
                'department' => $contact['address']['department'] ?? null,
                'country'    => $contact['address']['country']    ?? null,
                'zipCode'    => $contact['address']['zipCode']    ?? null,
            ], fn($v)=>$v!==null && $v!=='');
        }
        if (empty($client_address['city']) || empty($client_address['department']) || empty($client_address['country'])) {
            $defs = apply_filters('woo_alegra_default_address', [
                'country'    => 'Colombia',
                'department' => 'Bogotá D.C.',
                'city'       => 'Bogotá',
            ]);
            $client_address = array_merge(['address'=>'Calle'], $defs, $client_address);
        }
        $client_payload['address'] = $client_address;

        
        $due_date_str = $date_str;
        if ($paymentForm === 'CREDIT') {
            $dt = date_create_from_format('Y-m-d', $date_str) ?: new DateTime($date_str);
            $dt->modify('+15 days');
            $due_date_str = $dt->format('Y-m-d');
        }

        
        $is_electronic_series = isset($opts['number_template_id_is_electronic'])
            ? (bool)$opts['number_template_id_is_electronic']
            : true; 

        
        $invoice_data = [
            'client'        => $client_payload,
            'date'          => $date_str,
            'dueDate'       => $due_date_str,
            'items'         => $items,
            'observations'  => 'Pedido WooCommerce #'.$order->get_order_number(),
            'status'        => 'open',
            'paymentForm'   => $paymentForm,
            'paymentMethod' => $paymentMethod,
        ];
        
        if (!empty($opts['ubl21_enabled'])) {
            $invoice_data['operationType'] = 'STANDARD';
        }
        
        if (!empty($opts['number_template_id'])) {
            $invoice_data['numberTemplate'] = ['id' => (string)$opts['number_template_id']];
        }

        
        $invoice_data = apply_filters('woo_alegra_invoice_payload', $invoice_data, $order);

        
        list($doc_from_order2, $doc_type_from_order2) = $this->woo_alegra_get_order_document_and_type($order);
        $safe_name2     = $this->woo_alegra_build_safe_name($order);
        $ident_number2  = isset($client_payload['identification']) ? (string)$client_payload['identification'] : (string)$doc_from_order2;
        $ident_type2    = isset($client_payload['identificationType']) ? (string)$client_payload['identificationType'] : ($doc_type_from_order2 ?: 'CC');
        $required_client = [
            'id'                 => (int) $client_id,
            'name'               => $safe_name2,
            'identification'     => $ident_number2,
            'identificationType' => $ident_type2,
        ];
        if (!isset($invoice_data['client']) || is_int($invoice_data['client'])) {
            $invoice_data['client'] = $required_client;
        } else {
            $cli = (array) $invoice_data['client'];
            foreach ($required_client as $k => $v) {
                $is_missing = !array_key_exists($k, $cli);
                $is_empty   = !$is_missing && ($cli[$k] === null || $cli[$k] === '');
                if ($is_missing || $is_empty) $cli[$k] = $v;
            }
            $cli['id'] = (int)$cli['id'];
            $invoice_data['client'] = $cli;
        }

        $order->update_meta_data('_alegra_client_after_filters', wp_json_encode($invoice_data['client'], JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
        $order->update_meta_data('_alegra_invoice_payload_final', wp_json_encode($invoice_data, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
        $order->save();
        $order->add_order_note('✅ Paso 5: Payload completo. Ver meta _alegra_invoice_payload_final');

        
        $order->add_order_note('🔄 Paso 6: Enviando factura a Alegra API...');
        $this->log('=== PAYLOAD FINAL DE FACTURA ===: ' . wp_json_encode($invoice_data, JSON_PRETTY_PRINT), 'info');
        $order->add_order_note('📋 Payload factura (client): ' . wp_json_encode($invoice_data['client'], JSON_PRETTY_PRINT));
        $response = $api_client->create_invoice($invoice_data);

        if (!$response || !isset($response['id'])) {
            throw new Exception('Respuesta de Alegra sin ID de factura');
        }

        
        $order->update_meta_data('_alegra_invoice_id', $response['id']);
        if (!empty($response['numberTemplate']['number'])) {
            $order->update_meta_data('_alegra_invoice_number', $response['numberTemplate']['number']);
            $order->add_order_note('✅ Factura Alegra creada: #'.$response['numberTemplate']['number']);
        } else {
            $order->add_order_note('✅ Factura Alegra creada (ID '.$response['id'].')');
        }
        $order->save();
        $this->log('Factura creada exitosamente para pedido #'.$order_id.': '.$response['id']);

        
        try {
            $inv_snapshot = $api_client->request('invoices/'.(int)$response['id'], 'GET');
            if ($inv_snapshot) {
                $order->update_meta_data('_alegra_invoice_snapshot', wp_json_encode($inv_snapshot, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
                $order->save();
            }
        } catch (\Throwable $e) {
            $this->log('No se pudo obtener snapshot de factura: '.$e->getMessage(), 'warning');
        }

        
        try {
            $currency   = get_woocommerce_currency();
            $total_paid = (float) $order->get_total();

            $collection_payload = [
                'date'          => $date_str,
                'client'        => ['id' => (int) $client_id],
                'paymentForm'   => $paymentForm,
                'paymentMethod' => $paymentMethod,
                'currency'      => ['code' => $currency],
                'observations'  => 'Cobro automático WooCommerce del pedido #'.$order->get_order_number(),
                'amount'        => $total_paid,
                'invoices'      => [
                    ['id' => (int) $response['id'], 'amount' => $total_paid],
                ],
            ];
            $collection_payload = apply_filters('woo_alegra_collection_payload', $collection_payload, $order, $response);

            $order->update_meta_data('_alegra_collection_payload', wp_json_encode($collection_payload, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE));
            $order->save();

            $this->log('Registrando cobro Alegra: '.wp_json_encode($collection_payload), 'info');
            $col_resp = $api_client->create_collection($collection_payload);

            if (!empty($col_resp['id'])) {
                $order->update_meta_data('_alegra_collection_id', $col_resp['id']);
                $order->add_order_note('💰 Cobro registrado en Alegra (collection ID '.$col_resp['id'].'). Factura debe quedar "Cobrada".');
                $order->save();
            } else {
                $order->add_order_note('⚠️ Cobro no retornó ID. Verifica en Alegra.');
            }
        } catch (\Exception $e) {
            $msg = $e->getMessage();
            if (strpos($msg, '403') !== false || stripos($msg, 'forbidden') !== false) {
                $order->add_order_note('⚠️ Alegra devolvió 403 al registrar cobro (Collections). '
                    .'Puede ser falta de permisos del plan/tenant o del token API. '
                    .'La factura quedó creada, pero NO “cobrada”.');
                $this->log('Collections 403: '.$msg, 'error');
            } else {
                $this->log('Error registrando cobro: '.$msg, 'error');
                $order->add_order_note('⚠️ No se pudo registrar el cobro: '.$msg);
            }
        }

        
        
        $series_is_electronic = $is_electronic_series;
        if (isset($response['numberTemplate']['isElectronic'])) {
            $series_is_electronic = (bool)$response['numberTemplate']['isElectronic'];
        } elseif (isset($response['isElectronic'])) {
            $series_is_electronic = (bool)$response['isElectronic'];
        }

        $should_emit = apply_filters('woo_alegra_emit_to_dian', true, $order, $response);

        if ($should_emit && $series_is_electronic) {
            $invoice_id = (int) $response['id'];
            $emit_ok = false; $emit_errs = [];

            
            try {
                $this->log('Intentando emisión DIAN vía /invoices/'.$invoice_id.'/e-invoice', 'info');
                $emit_resp = $api_client->request('invoices/'.$invoice_id.'/e-invoice', 'POST');
                $emit_ok = !empty($emit_resp);
            } catch (\Throwable $e) { $emit_errs[] = 'e-invoice: '.$e->getMessage(); }

            
            if (!$emit_ok) {
                try {
                    $this->log('Intentando emisión DIAN vía /e-invoicing/invoices/'.$invoice_id.'/send', 'info');
                    $emit_resp = $api_client->request('e-invoicing/invoices/'.$invoice_id.'/send', 'POST');
                    $emit_ok = !empty($emit_resp);
                } catch (\Throwable $e) { $emit_errs[] = 'e-invoicing: '.$e->getMessage(); }
            }

            if ($emit_ok) {
                $order->add_order_note('📤 Envío electrónico a DIAN solicitado.');
                $order->save();
            } else {
                $order->add_order_note('⚠️ No se pudo invocar la emisión a DIAN (revisa endpoints/plan). Intentos: '.implode(' | ', $emit_errs));
            }
        } else {
            $order->add_order_note('↩️ Emisión DIAN omitida (serie no electrónica o filtro la desactivó).');
        }

    } catch (Exception $e) {
        $error_msg = $e->getMessage();
        $this->log('Error al crear factura para pedido #'.$order_id.': '.$error_msg, 'error');
        $order->add_order_note('❌ ERROR: ' . $error_msg);
        return;
    }
}

¡Hola! ¿Escribiste a nuestro equipo de soporte? Si aún no has recibido apoyo, puedes crear un ticket en este formulario:
https://3ogwa.share.hsforms.com/29zyip6JURk-iS6hOg69zIw