Skip to main content

Subscription and Credits

This guide explains the Face2Social subscription model, credit system, and how payment gating works in the search flow.


Subscription plans​

Retrieve the list of available plans with GET /subscription/plans. This endpoint is public (no token required):

curl https://dashboard.face2social.com/api/v1/subscription/plans

The response is an array of SubscriptionPlan objects. Each plan has id, title, price, interval and credits, plus optional display fields (description, features, badge, discount, savings).

Start a subscription​

curl -X POST https://dashboard.face2social.com/api/v1/subscription/start/{planId} \
-H "Authorization: Bearer <your-token>"

The {planId} path parameter is taken from the plans list. The response contains checkout_url — the Stripe checkout page the user opens to pay. An optional returnTo query parameter accepts a relative path (e.g. search/abc123/matches) to redirect the user back after successful payment.

Check current subscription​

curl https://dashboard.face2social.com/api/v1/subscription/info \
-H "Authorization: Bearer <your-token>"

Returns {subscription, portalUrl} with the active subscription details. Credit balance is available separately via GET /credits.

Cancel​

curl -X POST https://dashboard.face2social.com/api/v1/subscription/cancel \
-H "Authorization: Bearer <your-token>"

Manage (Stripe billing portal)​

curl https://dashboard.face2social.com/api/v1/subscription/manage \
-H "Authorization: Bearer <your-token>"

Returns a Stripe billing portal URL where the user can manage payment methods, invoices, and billing details.

Sync after checkout​

If the user completes a Stripe checkout session externally (e.g. via an email link), sync the subscription state by passing the csi query parameter to:

GET /subscription/sync-by-session?csi=<id>

Credits​

Credits are the currency for search results. Each successful search unlock costs one credit.

Check your credit balance​

curl https://dashboard.face2social.com/api/v1/credits \
-H "Authorization: Bearer <your-token>"

Returns a CreditsInfo object:

FieldMeaning
availableCredits the user can spend now
totalplan + referral credits
planCredits from the subscription plan
referralReferral credits — spent first, carried over to the next month
usedCredits used this month
searchesUsed / searchesLimitFree-search usage for users without a subscription

Search limit for users without a subscription​

Starting a search (POST /search/upload) never spends a credit, but a user without an active subscription can start only a limited number of searches. After that, upload returns 402 Payment Required ("search limit reached") and GET /users/me reports canSearch: false until the user buys a plan.


How credits are charged: payment_stage​

The server-side configuration key common.payment_stage controls where in the search flow a credit is deducted. Clients read the active mode from the paymentStage field of GET /users/me (missing or null means selection). There are two modes:

payment_stage=selection​

A credit is deducted when the user calls POST /search/{searchId}/select to confirm the matches. If credits.Available == 0, the API returns 402 Payment Required at this step and the results remain locked.

payment_stage=results​

The credit is not deducted at selection. Instead it is deducted (or the results are blurred) when the user calls GET /search/{searchId}/results. This call never returns 402: without a credit it returns 200 with isBlurred: true and masked profile data.

The paywall decision at results-time uses two signals fetched in parallel: credits.Available and results_credit_deducted (a per-search flag set once the credit has been charged):

credits.Availableresults_credit_deductedOutcome
0falseBlurred — paywall: no credit, results never unlocked
0trueUnblurred — already paid; revisiting stays unlocked
> 0falseDeduct now, return unblurred results
> 0trueUnblurred — idempotent (no double charge)
Important

With payment_stage=results and credits.Available == 0, always check results_credit_deducted before blurring — otherwise a results view that the user already paid for gets re-blurred on revisit.


Offers​

The API exposes an offer system for promotional or upsell pricing:

  • GET /offer — returns the current offer assigned to the authenticated user (e.g. a discounted subscription plan).
  • GET /offer/{hash} — resolves an email deep-link to start checkout for an assigned offer.

Referrals​

The API includes a referral program:

  • POST /ref/{code} — saves a referral or partner-link code to the session (call before sign-up to attribute the new user). An unknown partner code returns 404.
  • GET /referral/info — returns referral information for the authenticated user.
  • POST /referral/acknowledge — acknowledges that the user has viewed a referral hint.

Error codes​

HTTP statusMeaning
402 Payment RequiredOn POST /search/upload: the search limit for users without a subscription is reached. On POST /search/{searchId}/select (only with payment_stage=selection): no credits available; the selection is rolled back, so the call can be repeated after buying credits. GET /search/{searchId}/results never returns 402; it blurs instead
400 Bad RequestOn select: matches already selected, or more than maxSelectable IDs. On results: matches not selected yet
401 UnauthorizedToken missing, expired, or invalid
404 Not FoundPlan or subscription not found