We want to call our API route to create a new Stripe customer anytime a new user signs into our application. Since this triggers an insert on our
profile table, we can use hooks in Supabase to listen to insert events and call our API route.
Function hooks in Supabase are similar to PostgreSQL triggers, however, rather than executing a function, we can call a HTTP endpoint. Since our Next.js application is running locally on our machine it is not possible for Supabase to send a HTTP request directly to our API route.
Ngrok is a simple tool that allows us to tunnel traffic from a publicly accessible URL on the internet, through to our Next.js application running locally.
In order for our API route to process the request, we need to tell our Supabase hook to also send our
API_ROUTE_SECRET. Query parameters can be declared as HTTP params for our hook.
Lastly, we want our Stripe customer to be associated with our user via their email address.
Instructor: [0:00] We want to call this API route to create a new Stripe customer for us, any time a new row is added to the profile table. In order to do this, we're going to use Supabase's function hooks, which can be found under the database menu.
[0:11] Let's enable hooks for this project. Now we can create a function hook. The name of our function hook is going to be getStripeCustomer. Similarly to Postgres triggers, we can listen to different events that occur on particular tables. We would like to watch the profile table, and call this endpoint any time an insert event happens.
[0:30] Our type of hook is going to be a HTTP request. We're going to select the POST method, and put in the URL to our API route. Because this function hook will be executed by the Supabase server, it doesn't actually know what our localhost is. Therefore, we need to tunnel traffic from a public Internet address through to port 3000 on our localhost machine.
[0:51] To do this, we're going to use a tool called ngrok. Since we'll need to keep this process running while we're testing in development, I'm going to start a new process. I'm going to install ngrok globally with the -g flag. Once that's finished, we can tell ngrok to route all HTTP traffic to port 3000. It will then give us a temporary public URL that we can route traffic to.
[1:14] We can copy that from here and replace http://localhost over port 3000 with our new public address. Now any HTTP requests that this public address receives will be forwarded to our localhost over port 3000, which will be handled by our Next.js server running on port 3000.
[1:31] The last thing we need to remember to send to our API route is the API route secret, or our request will just get rejected with status 401. Let's grab that value from our .env file. It's going to be API route secret. We're going to pass this along as a HTTP param.
[1:48] The value is going to be this value. Let's click confirm to create our new function hook. To test this works, let's go delete the row from the profile table and then our Supabase user from the authentication tab. We can delete our previous customers from our Stripe dashboard.
[2:06] Back in our application, we can logout our current user by going to /logout and then navigating to /login. If we go back to our Supabase dashboard and refresh our users in the authentication pane, we will see we have our user back.
[2:21] If we check our profile table, we have an associated row for our new customer complete with our new Stripe customer ID, which matches the customer in our dashboard.
[2:31] Our customer ID is correct, but our customer doesn't have a name and we haven't been able to correctly associate an email with this customer. If we have a look at our API route, we're setting the email for our new Stripe customer based on the request.body.record.email.
[2:47] This record represents the row in our profile table, that has just been inserted, which doesn't have a column for email. Our email only exists on our auth.users table. If we want to pipe this through to Stripe, we just need to create a new column for email in our profile table. This is going to be of type, text. Let's click Save to add our new column.
[3:09] We then need to tell our Trigger function that there is an email that we want to pass across. We can do that by editing our function here. When we insert into public profile, we now also care about the email column, and we want to set that to the value, new.email. Let's click Confirm to update our function. Let's delete our test records again.
[3:37] When we go back to our application and log out and back in, we should see our new customer in Stripe, complete with an email address. Our customer ID should match our profile table's Stripe customer.
Hello Jon! I stuck in the function hook, when I try to login after writing the function returns this "Failed to invite user: Database error saving new user"... is there anyone can help ?
Hmmm. Very strange! One thing you can check is the logs in your Supabase dashboard. It is under Settings > Logs > Database. If that doesn't give you any more hints, email firstname.lastname@example.org and include your project ref (the part of your Supabase URL after
/project/), and hopefully someone will be able to take a look 👍
When I remove row level security in Profile table,
stripe_customer updates. But with it on, it doesn't. I added the 'read' row level security from prior lesson. Has something changed?
When I remove row level security in Profile table,
stripe_customerupdates. But with it on, it doesn't. I added the 'read' row level security from prior lesson. Has something changed?
Here is a link to the row-level security article on Supabase. Jon also has an in-depth video in that article that should answer your question. https://supabase.com/docs/guides/auth/row-level-security
"Hello Jon! I stuck in the function hook, when I try to login after writing the function returns this "Failed to invite user: Database error saving new user"... is there anyone can help ?"
I'm running into this as well. I followed the steps for creating the function hook and when I try logging in, I get an error:
I ran across this, and it solved part of my problem. I'm able to login but I'm still seeing errors. Not sure if it has to do with my local environment or not: https://github.com/supabase/supabase/issues/4883
When I remove row level security in Profile table, stripe_customer updates. But with it on, it doesn't. I added the 'read' row level security from prior lesson. Has something changed?
@George did you ever get that working?
Hey all 👋 At this point, RLS should not be enabled on the profiles table. Once this is enabled, we need to use the service role key when creating a Supabase client. This will bypass RLS, which is what we want because this is a server action, not based on a specific user.
Jump forward to this lesson for creating a service role Supabase client, and fixing this API route 👍
Just a heads up, "Function Hooks" has been renamed "Database Webhooks". Same function, just a new name 👍
Is there another way to do this without using hooks ? can we check if the profile just created after the login if its so call the create-stripe-customer from Login component?