GrinGhost est un provider OIDC custom + intermédiaire de paiement. Crée un site dans le dashboard, liste tes actions, GrinGhost valide chaque débit et gère les crédits universels.
De la création de compte au premier virement — voilà les 9 étapes pour être opérationnel sur GrinGhost.
1
Créer un compte GrinGhost
Connexion via Google OAuth sur gringhost.com. Ton compte est créé automatiquement.
2
Accepter les CGU/CGV
À la première ouverture du dashboard — acceptation obligatoire, horodatée et enregistrée.
3
Accepter les conditions développeur
À la première ouverture de l'espace développeur. Commission 10%, verrou 7j, préavis 30j, motifs de suspension.
4
Créer un site
Dashboard → Espace développeur → Nouveau site. Tu reçois clé API prod, clé API sandbox, OAuth client_id et client_secret.
5
Connecter ton compte Stripe
Dashboard dev → bannière « Connecter Stripe ». Stripe Express : Stripe gère le KYC et la vérification bancaire. Nécessaire pour recevoir tes payouts.
6
Enregistrer ton catalogue d'actions
Dashboard dev → ton site → + Action. Nom de l'action + coût en crédits. Le verrou tarifaire de 7j s'applique immédiatement.
7
Intégrer l'auth GrinGhost (OIDC)
Ajoute GrinGhost comme custom provider OIDC dans Supabase. Tes utilisateurs se connectent avec leur compte GrinGhost via un bouton « Continue with GrinGhost ».
8
Implémenter session-token + debit
Côté serveur : POST /api/site/session-token (route prepare). @gringhost/react vérifie le prix et affiche la confirmation. Côté serveur : POST /api/site/debit (route execute). Chaque crédit débité = consentement explicite prouvé.
9
Recevoir tes payouts
Dashboard dev → Retirer dès 50 000 crédits en attente (~$4.50). Virement direct sur ton compte Stripe sous 2–7 jours ouvrés.
GrinGhost est un provider OIDC complet. Ajoute-le dans Supabase comme custom provider — il auto-découvre tous les endpoints via son document de configuration.
1. Créer un site dans le dashboard GrinGhost
Dashboard → Espace développeur → Mes Sites → Nouveau site. Renseigne le nom et l'URL. Tu obtiens :
Clé API prod + Clé API sandbox — pour les appels backend
OAuth client_id + OAuth client_secret — pour le flux OIDC
Les clés sont affichées une seule fois à la création. Si tu les perds, utilise "Regénérer les clés" dans le dashboard (les anciennes sont invalidées immédiatement).
URL du site — GrinGhost valide que le redirect_uri passé lors du flux OAuth a le même origin que l'URL enregistrée. En dev, enregistre http://localhost:3000.
2. Créer ton catalogue d'actions
Avant d'appeler l'API, enregistre tes actions dans le dashboard : Dashboard → Mes Sites → ton site → Catalogue d'actions.
Chaque action a un nom unique, une description optionnelle, et un prix en crédits. GrinGhost n'autorisera aucun débit sur une action non enregistrée.
text
Exemple de catalogue :
analyze_image → 500 crédits (Analyser une image)
generate_text → 300 crédits (Générer du texte)
summarize → 200 crédits (Résumer un document)
Tu ne peux pas augmenter le prix d'une action dans les 7 jours suivant sa création ou sa dernière modification. Ce verrou protège tes utilisateurs.
3. Ajouter GrinGhost dans Supabase
Authentication → Sign In / Up → Social Providers → Add provider → Custom OAuth 2.0.
Champ
Dev (sandbox)
Prod (live)
Provider name
gringhost
gringhost
Issuer URL
https://www.gringhost.com
https://www.gringhost.com
Client ID
oauth_client_id
oauth_client_id
Client Secret
oauth_client_secret
oauth_client_secret
Supabase auto-découvre les endpoints via https://www.gringhost.com/.well-known/openid-configuration. Le même oauth_client_id et oauth_client_secret s'utilisent en dev et en prod — la différence se fait sur la clé API (prod vs sandbox).
4. Ajouter le bouton de connexion
Avec le package @gringhost/react (recommandé) — place GrinGhostButton une fois dans ton header. Il gère login, menu, solde et confirmation automatiquement :
ts
npm install @gringhost/react
ts
// app/providers.tsx
'use client'
import { GrinGhostProvider } from '@gringhost/react'
import { createClient } from '@/lib/supabase/client'
const supabase = createClient()
export default function Providers({ children }: { children: React.ReactNode }) {
return <GrinGhostProvider supabase={supabase}>{children}</GrinGhostProvider>
}
// app/layout.tsx — importe Providers
// Puis dans ton header :
import { GrinGhostButton } from '@gringhost/react'
<GrinGhostButton /> // pas de props — gère tout
// app/auth/callback/route.ts
import { createClient } from '@/lib/supabase/server'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
if (code) {
const supabase = await createClient()
await supabase.auth.exchangeCodeForSession(code)
}
return NextResponse.redirect(origin + '/')
}
6. Récupérer le JWT GrinGhost côté serveur
Après le OAuth exchange, le JWT GrinGhost est stocké par Supabase comme provider_token. Tes routes serveur (prepare, execute) le lisent via le client Supabase server-side — il ne transite jamais côté client.
ts
// Dans toutes tes routes serveur (prepare, execute, credits…)
import { createClient } from '@/lib/supabase/server'
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser() // vérifie auth
const { data: { session } } = await supabase.auth.getSession()
const providerToken = session?.provider_token // JWT GrinGhost → body de /api/site/session-token
Ne jamais lire ni transmettre le provider_token côté client. Il est utilisé uniquement dans les routes serveur pour appeler /api/site/session-token.
7. Débiter des crédits — flux prepare/execute
Le débit suit un protocole en 4 temps : le serveur du dev génère un session token, @gringhost/react vérifie le prix directement depuis GrinGhost, l'utilisateur confirme dans GrinGhostButton, puis le serveur exécute le débit.
Route prepare — génère le session token côté serveur :
Côté client — useGrinGhostAction déclenche la confirmation dans GrinGhostButton :
ts
'use client'
import { useGrinGhost, useGrinGhostAction } from '@gringhost/react'
const { loadCredits } = useGrinGhost()
const { prepare } = useGrinGhostAction('/api/internal/mon-action/prepare')
const result = await prepare() // affiche la confirmation (prix vérifié, countdown 28s)
if (!result) return // annulé ou timeout
const res = await fetch('/api/internal/mon-action', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ input, session_token: result.sessionToken }),
})
if (res.status === 402) { window.open('https://www.gringhost.com/buy', '_blank'); return }
loadCredits() // rafraîchit le solde dans GrinGhostButton
Génère toujours un idempotency_key frais par tentative côté serveur (crypto.randomUUID()). En cas de retry réseau, GrinGhost retourne success: true sans débiter à nouveau.
8. Lire le solde de crédits
Avec @gringhost/react — le solde est chargé automatiquement à la connexion et rechargeable à la demande :
ts
'use client'
import { useGrinGhost } from '@gringhost/react'
const { credits, loadCredits } = useGrinGhost()
// credits est mis à jour automatiquement après chaque action
// loadCredits() force un rechargement depuis /api/internal/credits
Ou directement via les endpoints GrinGhost (authentifié par le JWT GrinGhost) :
Quand un utilisateur manque de crédits (402), redirige-le vers la page d'achat GrinGhost — le wallet est universel, les crédits achetés sont utilisables sur tous les sites :
ts
if (res.status === 402) {
window.open('https://www.gringhost.com/buy', '_blank')
}
Le catalogue est la liste de tes actions IA avec leur prix en crédits. GrinGhost refuse tout débit sur une action non enregistrée ou inactive.
Règles du catalogue
Chaque action a un nom unique, une description optionnelle, et un prix en crédits (entier positif)
Une action peut être désactivée (is_active: false) sans être supprimée
Le prix est verrouillé 7 jours après création ou modification — impossible d'augmenter pendant ce délai
Tu peux ajouter de nouvelles actions à tout moment
Afficher le prix avant débit
@gringhost/react gère ça automatiquement. Quand useGrinGhostAction appelle ta route prepare, le package vérifie le prix directement depuis GrinGhost, puis affiche la confirmation dans GrinGhostButton (action_name, credits_cost, countdown 28s). Aucun code supplémentaire côté dev.
Le prix affiché à l'utilisateur vient de /api/public/session-token-info — appelé directement depuis le navigateur vers GrinGhost, sans passer par ton serveur. Impossible de falsifier le montant montré.
Un session token est un jeton usage unique (TTL 30 secondes) créé depuis ton backend serveur. Il prouve que le débit correspond à une action enregistrée pour cet utilisateur — GrinGhost refuse tout appel à /api/site/debit sans ce token.
Pourquoi ce mécanisme ?
Empêche le dev de débiter en background sans action utilisateur
Le prix est fixé dans le token à la création — le dev ne peut pas le modifier entre session-token et debit
TTL 30 secondes — usage unique, pas de replay
Lié à un triplet (user_id, site_id, action_id) — non transférable
Le mode service permet à un utilisateur GrinGhost (ex : un restaurateur) de pré-autoriser un site à le débiter côté serveur, sans confirmation par action. Idéal pour les widgets chatbot, les SaaS à l'usage, ou tout flux où l'utilisateur final n'interagit pas directement avec GrinGhost.
Cas d'usage type
1
Le restaurateur crée un compte GrinGhost, achète des crédits.
2
Dans son dashboard GrinGhost → "Autorisations de service", il sélectionne ton site et fixe un budget total (ex. 500 000 crédits).
3
Il reçoit un service_token (ghsvc_xxx) — affiché une seule fois. Il le configure dans ton backend.
4
Ton backend débite ses crédits à chaque requête du chatbot, sans confirmation utilisateur.
5
Quand le budget est épuisé, le débit est refusé — le restaurateur recharge ou crée une nouvelle autorisation.
Côté backend — appel debit avec service_token
Remplace session_token par service_token + action_id. Pas de route prepare, pas de @gringhost/react — tout se passe côté serveur.
Le service_token n'est pas lié à un utilisateur final — c'est le restaurateur qui est débité, pas le visiteur du chatbot. Assure-toi que le restaurateur comprend qu'il paye pour chaque requête de ses clients.
Différence avec le mode session : le mode service est toujours live (pas de sandbox), le coût vient du catalogue (action_id), et il n'y a pas de GrinGhostButton ni de confirmation utilisateur. Le budget est contrôlé par le restaurateur via son dashboard.
Appelé depuis ton backend serveur (route prepare). Auth par x-api-key + JWT utilisateur (provider_token) dans le body. Ne jamais appeler depuis le navigateur — ça exposerait ta clé API.
Endpoint public — pas d'auth. Appelé directement depuis le navigateur par @gringhost/react pour vérifier le prix d'un token avant d'afficher la confirmation.
text
GET /api/public/session-token-info?token=<session_token>
Tu fixes le prix de chaque action dans le catalogue. Les crédits sont universels — l'utilisateur achète sur gringhost.com, pas sur ton site.
Tes gains : 90% des crédits consommés × $0,0001 — soit $0.000090 par crédit.
ts
// Calculer le coût en crédits d'une action
// 1 crédit = 0.0001 $ payé par l'utilisateur → tu reçois 0.000090 $
const coutReel = 0.00005 // $ — ton coût API (ex: GPT-4o-mini court)
const marge = 2 // ×2 par rapport à ton coût
const credits = Math.ceil(coutReel * marge / 0.0001) // = 1 (minimum 1)
Action
Coût API
×2
Crédits
Tu reçois
GPT-4o-mini court (~300 tok)
~$0.00005
$0.0001
1 cr
~$0.000090
GPT-4o-mini moyen (~1k tok)
~$0.0002
$0.0004
4 cr
~$0.00036
GPT-4o moyen (~2k tok)
~$0.005
$0.01
100 cr
~$0.009
DALL-E 3
~$0.04
$0.08
800 cr
~$0.072
Verrou tarifaire — Tu ne peux pas augmenter le prix d'une action dans les 7 jours suivant sa création ou sa dernière modification. Ce délai protège les utilisateurs contre toute dévaluation.
Tu reçois 90% des crédits consommés sur ton site. Les gains s'accumulent automatiquement — déclenche un payout depuis le dashboard quand tu atteins 50 000 crédits (~$4.50 après commission).
Pack acheté
Prix
GrinGhost (10%)
Tu reçois (90%)
Starter
$5.00
$0.50
$4.50
Standard
$20.00
$2.00
$18.00
Pro
$50.00
$5.00
$45.00
La commission est calculée sur les crédits consommés, pas sur les crédits achetés. Les crédits non dépensés ne génèrent pas de revenus.
Connecter ton compte Stripe
Avant de pouvoir retirer tes gains, tu dois connecter un compte Stripe via Stripe Connect Express. GrinGhost s'occupe de l'intégration — tu n'as pas à créer un compte marchand Stripe indépendant.
1Dashboard dev → bannière violette « Connecte ton compte Stripe »
2Redirigé vers Stripe Express Onboarding — Stripe vérifie ton identité et ton RIB/IBAN
3Retour sur le dashboard → bouton « Retirer » activé sur chaque site
4Clique « Retirer » dès 50 000 crédits en attente → virement réel sous 2–7 jours ouvrés
GrinGhost utilise Stripe Connect Express — Stripe gère le KYC, la vérification bancaire et la conformité. Tu n'as pas à gérer la conformité PCI. Minimum de retrait : 50 000 crédits.
Le starter contient un fichier CLAUDE.md que Claude Code lit au démarrage. Il connaît déjà GrinGhost — tu décris ton produit, il construit.
Ce que Claude Code sait déjà
Le pattern exact pour toute route IA payante (session-token, debit, gestion 402)
Quels fichiers ne pas toucher (auth, session, crédits)
Comment récupérer l'utilisateur connecté côté serveur et client
La différence sandbox / live et les variables d'env
Démarrer
bash
npm install -g @anthropic-ai/claude-code
cd gringhost-nextjs-starter
claude
Exemples de prompts
text
"Ajoute un assistant de rédaction SEO. L'utilisateur entre un sujet,
reçoit 5 titres. Coût : 300 crédits (action: generate_titles)."
"Crée une page /summarize. L'utilisateur colle un texte, clique Résumer.
Coût : 200 crédits (action: summarize)."
Claude Code ne modifiera pas l'auth ni la logique GrinGhost existante. Voir le starter →