πTerms & Conditions
Projects can require users to accept a terms document before participating in a program. Fuul records the acceptance once per wallet and makes it readable from any surface holding a project API key, so a user who already accepted in your app is not prompted again in the affiliate portal.
This feature is configured by Fuul, not from the dashboard. Reach out at ecosystem@fuul.xyz to enable it for your project and set your terms document URL. Until it is enabled, GET /status reports terms_acceptance_required: false and POST /accept returns 400.
How it works
Your frontend calls
GET /statusfor the connected walletIf
terms_acceptance_requiredistrueandterms_acceptedisfalse, you show the document atterms_document_urland ask the user to acceptYour backend calls
POST /accept, declaring which surface collected the acceptanceEvery other surface reading
/statusfor that wallet now seesterms_accepted: true
The record attests that a system asserted the acceptance. Neither endpoint carries a user session, and nothing cryptographically binds the wallet to the request, so this is not a signature scheme. If you need proof of possession, verify the wallet yourself before calling /accept.
Endpoints
Base path: /api/v1/project-terms-conditions
/accept
POST
terms_conditions:write
Records an acceptance. Returns 201
/status
GET
terms_conditions:write or service_role
Returns the project's config plus one wallet's acceptance state
Both endpoints return the same response shape, so an accept never needs a follow-up read.
Request fields
user_identifier
Both
The wallet address
user_identifier_type
Both
evm_address, solana_address, or xrpl_address
source
Accept only
partner_site, affiliates_portal, or other. Required, no default
The accepted identifier types are narrower than the platform's full list. Only evm_address, solana_address, and xrpl_address are valid here. sui_address is rejected with a 400 even though it appears in identifier type lists elsewhere in these docs, and email / uuid are rejected as well: an acceptance is anchored to a wallet.
Response
terms_acceptance_required
Whether the gate is on for this project
terms_document_url
The document currently in force. Only present when the gate is on
terms_accepted
Whether this wallet has already accepted
accepted_at
When the acceptance was recorded, on the server clock. null if not accepted
Example
Check status before showing your program UI:
Record the acceptance from your backend:
Idempotency
Acceptance is unique per (project, wallet, identifier type). Calling /accept again for a wallet that already accepted returns 201 and leaves the original record untouched: source, the document URL, and accepted_at stay frozen to whichever surface accepted first.
This means you can call /accept without checking /status first, and retries are safe.
What acceptance does and does not cover
Scope
One general acceptance per wallet, not per document revision. There is no version field
Document changes
Each record snapshots the document URL that was live when the user accepted. Publish every revision under a new immutable URL so that snapshot stays meaningful
Re-prompting
Changing your document text does not re-prompt users who already accepted
Turning the gate off
Existing records are kept and become inert, not deleted. Turning the gate back on does not re-prompt anyone who already accepted
If you overwrite your terms document at the same URL instead of publishing a new one, the stored records will point at a document whose contents have changed since users accepted it. Use a versioned path such as /terms-v2.pdf.
Related
Collecting tax forms from affiliates is a separate flow with its own gate β Tax Information
Programs that require users to accept individual payouts before claiming β Claim Flow Integration
Last updated