Stripe GraphQL API
Query Stripe data through your GraphQL API using @nhost/stripe-graphql-js
Stripe GraphQL payments subscriptions invoices remote schema billingThe @nhost/stripe-graphql-js package lets you expose Stripe’s API as a GraphQL Remote Schema. Once connected, you can query Stripe customers, subscriptions, invoices, payment methods, and more alongside your existing data in a single GraphQL request.
Architecture
Section titled “Architecture”sequenceDiagram actor C as Client participant G as GraphQL Engine participant F as Nhost Function<br/>(stripe-graphql-js) participant S as Stripe API
C->>G: GraphQL query { stripe { customer { ... } } } G->>F: Forward remote schema query F->>F: Verify JWT / admin secret F->>F: Run isAllowed() check F->>S: Stripe API request S-->>F: Stripe data F-->>G: GraphQL response G-->>C: Unified responseYour client sends a single GraphQL query to the GraphQL engine. The engine identifies the stripe field as a Remote Schema and forwards it to the Nhost Function running @nhost/stripe-graphql-js. The function authenticates the request, checks permissions, fetches data from Stripe, and returns it through the GraphQL engine back to the client.
-
Install the package
In your Nhost project, install the dependency:
Terminal window pnpm add @nhost/stripe-graphql-js -
Create the serverless function
Create a file at
functions/graphql/stripe.ts:import { createStripeGraphQLServer } from '@nhost/stripe-graphql-js';const server = createStripeGraphQLServer();export default server; -
Add the Stripe secret key
First, store your Stripe secret key as a project secret. In the Nhost dashboard go to Settings > Secrets, or use the CLI:
Terminal window nhost secrets create STRIPE_SECRET_KEY sk_live_...Then expose it as an environment variable in
nhost/nhost.toml:[[global.environment]]name = 'STRIPE_SECRET_KEY'value = '{{ secrets.STRIPE_SECRET_KEY }}' -
Register as a Remote Schema
Add the function as a Remote Schema in
nhost/metadata/remote_schemas.yaml:- name: stripedefinition:url: '{{NHOST_FUNCTIONS_URL}}/graphql/stripe'timeout_seconds: 60customization: {}Or add it through the dashboard under GraphQL > Remote Schemas, using
{{NHOST_FUNCTIONS_URL}}/graphql/stripeas the URL.
Available Operations
Section titled “Available Operations”Queries
Section titled “Queries”All queries are namespaced under the stripe field:
| Query | Arguments | Description |
|---|---|---|
stripe.customer | id (required) | Get a single customer by ID |
stripe.customers | email, limit, startingAfter, endingBefore | List customers with optional filtering and pagination |
A customer object includes nested fields that resolve additional Stripe data:
| Nested Field | Description |
|---|---|
subscriptions | Customer’s active subscriptions |
invoices | Customer’s invoices |
paymentMethods | Customer’s payment methods (accepts type, limit, startingAfter, endingBefore) |
paymentIntents | Customer’s payment intents |
charges | Customer’s charges |
Additional root queries (admin only):
| Query | Arguments | Description |
|---|---|---|
stripe.connectedAccount | id (required) | Get a connected account |
stripe.connectedAccounts | — | List all connected accounts |
Mutations
Section titled “Mutations”| Mutation | Arguments | Description |
|---|---|---|
stripe.createBillingPortalSession | customer (required), returnUrl, configuration, locale | Create a Stripe Billing Portal session |
Example Queries
Section titled “Example Queries”Fetch a customer with subscriptions and payment methods
Section titled “Fetch a customer with subscriptions and payment methods”query { stripe { customer(id: "cus_ABC123") { id name email subscriptions { data { id status items { data { price { unitAmount currency product { name } } } } } } paymentMethods(type: card) { data { id card { brand last4 expMonth expYear } } } } }}List invoices for a customer
Section titled “List invoices for a customer”query { stripe { customer(id: "cus_ABC123") { invoices { data { id status amountDue amountPaid currency created hostedInvoiceUrl invoicePdf } } } }}Create a billing portal session
Section titled “Create a billing portal session”mutation { stripe { createBillingPortalSession( customer: "cus_ABC123" returnUrl: "https://myapp.com/account" ) { url } }}Authorization
Section titled “Authorization”By default, only admin requests (those with a valid admin secret header) are allowed. You can provide a custom isAllowed function to implement fine-grained access control:
import { createNhostClient, withAdminSession,} from '@nhost/nhost-js';import { Context, createStripeGraphQLServer } from '@nhost/stripe-graphql-js';
const nhost = createNhostClient({ subdomain: process.env['NHOST_SUBDOMAIN']!, region: process.env['NHOST_REGION']!, configure: [ withAdminSession({ adminSecret: process.env['NHOST_ADMIN_SECRET']!, }), ],});
const server = createStripeGraphQLServer({ isAllowed: async (stripeCustomerId: string, context: Context) => { const { isAdmin, userClaims } = context;
// Admins can access any customer if (isAdmin) { return true; }
// Otherwise, verify the user owns this Stripe customer. // For example, look up the mapping in your database: const userId = userClaims?.['x-hasura-user-id']; if (!userId) { return false; }
// Query your database to check if this user owns the Stripe customer const resp = await nhost.graphql.request({ query: ` query ($userId: uuid!, $stripeCustomerId: String!) { users(where: { id: { _eq: $userId }, metadata: { _contains: { stripeCustomerId: $stripeCustomerId } } }) { id } } `, variables: { userId, stripeCustomerId }, }); return (resp.body.data?.users?.length ?? 0) > 0; },});
export default server;The isAllowed function receives:
stripeCustomerId: The Stripe customer ID being accessedcontext: An object containing:isAdmin— Whether the request has admin privilegesuserClaims— The decoded JWT claims (includesx-hasura-user-id,x-hasura-default-role,x-hasura-allowed-roles).
The function is called for customer-scoped queries and mutations. Admin-only queries like connectedAccounts check isAdmin directly.
Configuration
Section titled “Configuration”The createStripeGraphQLServer function accepts these options:
| Option | Type | Default | Description |
|---|---|---|---|
isAllowed | (stripeCustomerId, context) => boolean | Promise<boolean> | Admin-only | Custom authorization function |
cors | CORSOptions | — | CORS configuration |
graphiql | boolean | false | Enable the GraphiQL interface |
maskedErrors | boolean | true | Mask error details in responses |
Environment Variables
Section titled “Environment Variables”| Variable | Required | Description |
|---|---|---|
STRIPE_SECRET_KEY | Yes | Your Stripe API secret key |
NHOST_JWT_SECRET | Auto | Set automatically by Nhost. Used to verify user JWTs |
NHOST_ADMIN_SECRET | Auto | Set automatically by Nhost. Used to verify admin requests |
NHOST_WEBHOOK_SECRET | Auto | Set automatically by Nhost. Used to verify internal requests from the GraphQL engine |