getsafepay / safepay-node

Safepay node.js client
MIT License
6 stars 3 forks source link

createSubscription function does not exists #20

Open hiraaziz opened 9 months ago

hiraaziz commented 9 months ago

I'm submitting a bug report

image

What is the current behavior?

When I try to create a subscription using the Safepay NodeJS SDK, I receive a TypeError indicating that safepay.checkout.createSubscription is not a function.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem

Set up a Next.js 13 API route. Install and import @sfpy/node-sdk. Initialize Safepay with the given credentials. Call the safepay.checkout.createSubscription method. Observe the error in the console.

What is the expected behavior?

The safepay.checkout.createSubscription method should execute successfully, and I should be able to generate a subscription URL without encountering any errors.

What is the motivation / use case for changing the behavior?

To successfully integrate Safepay subscription payments into my application.

Please tell us about your environment:

Browser: Chrome (latest version)

Environment: Sandbox

ziyadparekh commented 9 months ago

hi @hiraaziz thanks for reporting this bug.

This is due to the subscriptions functionality in the SDK not being published to NPM. I have just published a new version of the node SDK to npm so if you reinstall it you should be able to play around with subscriptions.

Please note that we have pushed a major version upgrade so make sure you are installing @sfpy/node-sdk@3.0.0

Let me know if this works

hiraaziz commented 9 months ago

@ziyadparekh Is this subscription feature is available only to those who have signed for production or I can use in test mode? because Iam getting the same error.

ziyadparekh commented 9 months ago

@hiraaziz you can use it with a sandbox account.

Can you please

hiraaziz commented 8 months ago

Sure,

  1. Here is the sdk version Iam using: image

  2. Here is the configuration : image

  3. Public API KEY: sec_a1732c22-bc53-4ba5-8928-533d6e506e37

  4. This is the error Iam getting: image

ziyadparekh commented 8 months ago

Thanks @hiraaziz

I have published a new minor version 3.0.1. Can you try again? On our side all the tests are working fine including tests for subscriptions.

Apologies for the trouble you're facing but would you mind re-installing and trying again? making sure the version is 3.0.1

ziyadparekh commented 8 months ago

@fatimaaurangzeb0640 Please see what the issue could be so we can help @hiraaziz out

hiraaziz commented 8 months ago

Now its working fine. @ziyadparekh

hiraaziz commented 8 months ago

@fatimaaurangzeb0640 How to confirm subscription through code?

ziyadparekh commented 8 months ago

Hey @hiraaziz subscriptions have to confirmed by the customer not the merchant. When you use the SDK to create a subscription, the URL you receive in the response is what your system has to redirect the customer to.

To test it out you should console log the URL and paste it in your browser.

Once your browser opens the checkout page, you will be prompted to

  1. create a Safepay account
  2. save a card
  3. subscribe to the plan

let me know if this helps

hiraaziz commented 8 months ago

@ziyadparekh 1. I need to know if customer successfully subscribed then after redirecting him to success page I want to add his id into db but I need to confirm his subscription with some API not via merchant dashboard.

  1. Can you please tell how can I get the subscription id of customer on the client side after subscribing - any API for this. We have only auth token and planid!

  2. Is there any other guide for developers other than this readme file?

ziyadparekh commented 8 months ago

Hi @hiraaziz whenever a new subscription is entered into by your customer, a webhook is fired to your backend indicating the details of the subscription. In order for Safepay to send the webhook, you first have to subscribe to the webhook through your dashboard.

  1. Navigate to the developers section of your dashboard and then go the Endpoints subsection.
  2. From there, you may first have to enable webhooks, but after that click on Add an Endpoint.
  3. Next, enter the URL of an endpoint that lives on your server where you wish to receive the webhooks. Make sure this is not a localhost URL. If you are developing on localhost, please use Ngrok and use that URL
  4. After creating the Endpoint, click on the Action Button on the row (button with 3 dots) and click on "Details".
  5. Inside the modal that opens (wait for the modal to load) you can select the events you are interested in receiving. For subscriptions you should subscribe to the following events:
    • subscription:created
    • subscription:unpaid
    • subscription:ended
    • subscription_payment:complete
    • subscription_payment:failed
  6. Its your decision whether you want to handle all of these events through one URL or create multiple endpoints for each type of event.

We are working on more comprehensive documentation for Webhooks, but for now the JSON for a subscription:created event looks like this

{
  "subscription": {
    "token": "sub_68cc8016-9bc0-4394-90d5-5501fdb4d805",
    "plan_id": "plan_22933989-a533-44d6-80d2-c1816571f451",
    "user_id": "user_4fb559b5-97d3-4ea2-9240-cc3f88ea374f",
    "instrument_id": "tms_478dc98a-abb3-4889-ab95-a89e9184d30c",
    "status": 7,
    "billing_cycle_anchor": {
      "seconds": 1698049985,
      "nanos": 960441887
    },
    "price_amount": 300000,
    "price_currency": "PKR",
    "balance": "0",
    "start_date": {
      "seconds": 1698049985,
      "nanos": 960441887
    },
    "trial_start_date": {
      "seconds": 1698049985,
      "nanos": 960441887
    },
    "trial_end_date": {
      "seconds": 1698049985,
      "nanos": 960441887
    },
    "created_at": {
      "seconds": 1698049985,
      "nanos": 960441887
    },
    "updated_at": {
      "seconds": 1698049985,
      "nanos": 960441887
    },
    "plan": {
      "token": "plan_22933989-a533-44d6-80d2-c1816571f451",
      "merchant_api_key": "sec_edeade52-46aa-483b-b87d-009d3ce41554",
      "name": "1-Bill",
      "amount": 300000,
      "currency": "PKR",
      "product": "AX-002",
      "type": 1,
      "created_at": {
        "seconds": 1694499808
      },
      "updated_at": {
        "seconds": 1694499808
      },
      "active": true,
      "number_of_billing_cycles": 1
    },
    "number_of_billing_cycles": 1,
    "merchant_api_key": "sec_edeade52-46aa-483b-b87d-009d3ce41554"
  }
}

Once you receive this event on your side, you can mark the relevant IDs from this object in your DB to create a new subscription

hiraaziz commented 8 months ago

@ziyadparekh subscription activation takes weeks in sandbox account.. Is this same for production account?

fatimaaurangzeb0640 commented 8 months ago

hey @hiraaziz what does the subscription status say before it becomes active?

hiraaziz commented 8 months ago

@fatimaaurangzeb0640 it says trailing. In sandbox account, After few weeks I got email that says my subscription is now activated. Then the status was changed to active. How much time subscription activation takes in production account.

fatimaaurangzeb0640 commented 8 months ago

@hiraaziz In both sandbox and production, the subscription becomes active after the trial period is over. When the subscription's trial period is going, its status is 'TRAILING' and when the trial period is over, the subscription finally becomes active, and the status is changed to 'ACTIVE'. This is also when you get charged for the first time.

If you want the subscription to be active right away, you should set the trial period to 0 (days) when creating the plan or you can even update the plan and set the trial period to 0. What is the trial period for the plan that you subscribed to?

hiraaziz commented 8 months ago

@fatimaaurangzeb0640 got it. Kindly check this here is an endpoint for webhook

image

Is this line "const valid = safepay.verify.webhook(request)" correct? because I am getting error in this line. Error processign webhook.

here is subscription api

image
fatimaaurangzeb0640 commented 8 months ago

@hiraaziz hey can you please share two things with me:

  1. the request json object that you are trying to verify
  2. the error that you receive in your catch while verifying the request
hiraaziz commented 8 months ago

@fatimaaurangzeb0640 This is url : https://295plan.vercel.app/payment I have set trial period to 0 , now when I subscribe it says incomplete status

image

this is error :

image

This is request json : NextRequest [Request] {

settingsObject: { baseUrl: undefined, origin: [Getter], policyContainer: [Object] }

},

method: 'POST',
localURLsOnly: false,
unsafeRequest: false,
body: { stream: undefined, source: null, length: null },
client: { baseUrl: undefined, origin: [Getter], policyContainer: [Object] },
reservedClient: null,
replacesClientId: '',
window: 'client',
keepalive: false,
serviceWorkers: 'all',
initiator: '',
destination: '',
priority: null,
origin: 'client',
policyContainer: 'client',
referrer: 'client',
referrerPolicy: '',
mode: 'cors',
useCORSPreflightFlag: true,
credentials: 'same-origin',
useCredentials: false,
cache: 'default',
redirect: 'follow',
integrity: '',
cryptoGraphicsNonceMetadata: '',
parserMetadata: '',
reloadNavigation: false,
historyNavigation: false,
userActivation: false,
taintedOrigin: false,
redirectCount: 0,
responseTainting: 'basic',
preventNoCacheCacheControlHeaderModification: false,
done: false,
timingAllowFailed: false,
headersList: HeadersList {
  cookies: null,
  [Symbol(headers map)]: [Map],
  [Symbol(headers map sorted)]: [Array]
},
urlList: [ [URL] ],
url: URL {
  href: 'https://295plan.vercel.app/api/webhooks',
  origin: 'https://295plan.vercel.app',
  protocol: 'https:',
  username: '',
  password: '',
  host: '295plan.vercel.app',
  hostname: '295plan.vercel.app',
  port: '',
  pathname: '/api/webhooks',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
}

}, [Symbol(signal)]: AbortSignal { aborted: false }, [Symbol(abortController)]: AbortController { signal: AbortSignal { aborted: false } }, [Symbol(headers)]: HeadersList { cookies: null, [Symbol(headers map)]: Map(28) { 'accept' => [Object], 'accept-encoding' => [Object], 'connection' => [Object], 'content-length' => [Object], 'content-type' => [Object], 'forwarded' => [Object], 'host' => [Object], 'user-agent' => [Object], 'x-forwarded-for' => [Object], 'x-forwarded-host' => [Object], 'x-forwarded-proto' => [Object], 'x-matched-path' => [Object], 'x-real-ip' => [Object], 'x-sfpy-signature' => [Object], 'x-vercel-deployment-url' => [Object], 'x-vercel-forwarded-for' => [Object], 'x-vercel-id' => [Object], 'x-vercel-ip-country' => [Object], 'x-vercel-ip-country-region' => [Object], 'x-vercel-ip-latitude' => [Object], 'x-vercel-ip-longitude' => [Object], 'x-vercel-ip-timezone' => [Object], 'x-vercel-proxied-for' => [Object], 'x-vercel-proxy-signature' => [Object], 'x-vercel-proxy-signature-ts' => [Object], 'x-vercel-sc-basepath' => [Object], 'x-vercel-sc-headers' => [Object], 'x-vercel-sc-host' => [Object] },

  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array], [Array], [Array],
  [Array]
]

},

cookies: RequestCookies { _parsed: Map(0) {}, _headers: [HeadersList] },
geo: {},
ip: undefined,
nextUrl: NextURL { [Symbol(NextURLInternal)]: [Object] },
url: 'https://295plan.vercel.app/api/webhooks'

} }

Error: Error processing webhook: TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined at new NodeError (node:internal/errors:405:5) at Function.from (node:buffer:333:9) at Verify.webhook (/var/task/.next/server/chunks/2152.js:769:27) at POST (/var/task/.next/server/app/api/webhooks/route.js:129:38) at /var/task/.next/server/chunks/5501.js:5294:43 at /var/task/.next/server/chunks/5501.js:6161:36 at NoopContextManager.with (/var/task/.next/server/chunks/5501.js:583:30) at ContextAPI.with (/var/task/.next/server/chunks/5501.js:253:58) at NoopTracer.startActiveSpan (/var/task/.next/server/chunks/5501.js:1176:34) at ProxyTracer.startActiveSpan (/var/task/.next/server/chunks/5501.js:1216:36) { code: 'ERR_INVALID_ARG_TYPE' }

fatimaaurangzeb0640 commented 8 months ago

hey @hiraaziz please bear with me while I am trying to see on my side why you are getting this error. will get back to you as soon as I can

fatimaaurangzeb0640 commented 8 months ago

hey @hiraaziz i looked into the issue and i think you need to parse your request object like this since you are using Next:

const body = await request.json();

can you please do this and share with me what you get? or is this how you are already doing it? here's the source for this solution: https://github.com/vercel/next.js/discussions/46483