skip to Main Content

I’m trying to implement authorize and pay later flow for my Next.js 14 app, but I’m having few problems.

Client side, I have this:

export const PPButton: FC<PaypalButtonProps> = ({ amount }) => {
const [orderId, setOrderId] = useState<string>()
  const createOrder = (data: Record<string, unknown>, actions: any) => {
    return actions.order
      .create({
        intent: 'AUTHORIZE',
        purchase_units: [
          {
            amount: {
              value: amount,
            },
          }
        ]
      })
      .then((orderID: string) => {
        setOrderId(orderID)
        return orderID;
      })
      .catch((error: any) => {
        console.error('Error creating order:', error);
        toast.error('Error creating order');
      });
  }

  const onApprove = (data: any, actions: any) => {
    console.log('data', data);
    return actions.order.authorize().then((details: any) => {
      console.log('Authorization details:', details);
      toast.success('Payment authorized');
    }).catch((error: any) => {
      console.error('Error authorizing order:', error);
      toast.error('Error authorizing order');
    });
  }

  async function onCapture () {
    return fetch(`${process.env.NEXT_PUBLIC_HOST}/api/paypal/captureOrder`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        orderId
      }),
    })
      .then((response) => response.json())
      .then((orderData) => {
        toast.success('Order paid successfully')
      })
  }

  return (
    <div>
      <PayPalScriptProvider options={{ intent: 'authorize', clientId: process.env.NEXT_PUBLIC_PAYPAL_CLIENT_ID!}}>
        <PayPalButtons
          createOrder={createOrder}
          onApprove={onApprove}
          /*  onError={this.onError}
            onClick={this.onClick}*/
        />
      </PayPalScriptProvider>
      <button onClick={onCapture}>Capture</button>
    </div>
  );
};

The route capture order calls this method:

    const accessToken = await generateAccessToken()
    // authorization id
    const url = `${base}/v2/payments/authorizations/${orderId}/capture`
    const response = await fetch(url, {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${accessToken}`,
      },
      body: JSON.stringify({
        payment_instruction: {
          disbursement_mode: "INSTANT",
          platform_fees: [
            {
              amount: {
                currency_code: "EUR",
                value: "1000"
              }
            }
          ]
        }
      })
    })

    return handleResponse(response)
  },

The authorization is successfull but I’m not able to capture the payment that has been created and authorized even though I pass the orderID generated by paypal when create the order and authorize it.
The error is always:

0] Error in capturing the Paypal order Error: {"name":"RESOURCE_NOT_FOUND","message":"The specified resource does not exist.","debug_id":"*******","details":[{"issue":"INVALID_RESOURCE_ID","description":"Specified resource ID does not exist. Please check the resource ID and try again."}],"links":[{"href":"https://developer.paypal.com/docs/api/payments/v2/#error-INVALID_RESOURCE_ID","rel":"information_link"}]}

Anyone has a clue about a workaround? Basically whenever I try to call Paypal API by my BE I get errors.

I’ve tried to create a route to call Paypal API but without success, it seems it just works on the FE, someone has faced the same issue?

2

Answers


  1. Chosen as BEST ANSWER

    Thank you. I've solve the issue. Now I'm trying to test the multiparty Paypal feature. I crete the referral for the partner, through this:

    createPartnerReferral: async function (email: string, tracking_id: string) {
        const accessToken = await generateAccessToken()
        const url = `${base}/v2/customer/partner-referrals`
        const response = await fetch(url, {
          method: 'post',
          headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${accessToken}`,
          },
          body: JSON.stringify({
            email: email,
            tracking_id: tracking_id,
            partner_config_override: {
              // redirect when onboarding completed
              return_url: '/',
              show_add_credit_card: true
            },
            api_integration_preference: {
              rest_api_integration: {
                integration_method: "PAYPAL",
                integration_type: "THIRD_PARTY",
                third_party_details: { features: ["PAYMENT", "REFUND", "PARTNER_FEE"] }
              }
            },
            products: [
              "EXPRESS_CHECKOUT"
            ],
            legal_consents: [
              {
                type: "SHARE_DATA_CONSENT",
                granted: true
              }
            ],
          }),
        })
    
        return handleResponse(response)
      },
    

    Then I try to crate the order:

    createMultipartyOrder: async function (price: number, email: string, fee) {
        const accessToken = await generateAccessToken()
        const url = `${base}/v2/checkout/orders`
        const response = await fetch(url, {
          method: 'post',
          headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${accessToken}`,
          },
          body: JSON.stringify({
            intent: 'AUTHORIZE',
            purchase_units: [
              {
                amount: {
                  currency_code: 'EUR',
                  value: String(price),
                },
                payee: {
                  email_address: email,
                },
      /*          payment_instruction: {
                  disbursement_mode: "INSTANT",
                },*/
                platform_fees: [
                  {
                    amount: {
                      currency_code: "EUR",
                      value: String(fee),
                    },
                  },
                ],
              },
            ],
          }),
        })
    
        return handleResponse(response)
      }
    }
    

    Then I do the capture:

    capturePayment: async function (authorization: string, price: string, fee: number) {
        const accessToken = await generateAccessToken()
        // authorization id
        const url = `${base}/v2/payments/authorizations/${authorization}/capture`
        const response = await fetch(url, {
          method: 'post',
          headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${accessToken}`,
          },
          body: JSON.stringify({
            amount: {
              currency_code: 'EUR',
              value: String(price),
            },
            is_final_capture: true,
            payment_instruction: {
              disbursement_mode: "INSTANT",
              platform_fees: [
                {
                  amount: {
                    currency_code: "EUR",
                    value: `${fee}`
                  }
                }
              ]
            }
          })
        })
    
        return handleResponse(response)
      },
    

    But I get error like the merchant cannot receive the payment, even though the referral API gave me 201 and all the rest. In my Sandbox accounts doesn't appear the new merchant neither. Does anyone has a clue about how to make it work in test mode?


  2. Do not use actions.order.create , this function is deprecated. Create the order from a server.

    The issue will most likely resolve itself when you create and capture the order with the same API credentials, from the same server-side environment.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search