Docs

Guides

Modular signup flow

Configure your signup form in the Hub and render it from GET /v1/signup-config.

Your users sign up through a form that you compose from modules (phone number, email, tag name, first and last name, birth date, country, referral code, acceptance of terms). You configure it in the Hub, under Settings, then Signup, and your app reads the published result from the API. The SDK's UI components render directly from it.

How configuration works#

  • You edit a draft, preview it, then publish it. Published versions are immutable and numbered 1, 2, 3, and you can roll back to an earlier one (it is republished under a new number).
  • The phone module is always present, enabled and required: it is the user's identity and it is verified by a one-time code.
  • Each enabled module needs a label in English and in your default language. Supported languages: en, fr, es, de, it, pt.

Read the published flow#

Retrieve the published signup flow with any key of the project. Only enabled modules are returned, already ordered.

curl "https://sdk.tilt-pay.com/v1/signup-config" \
  -H "Authorization: Bearer $TILT_PAY_API_KEY"
JSON
{
  "schema_version": 1,
  "version": 3,
  "default_locale": "en",
  "modules": [
    {
      "id": "phone",
      "input": "phone",
      "verification": "code",
      "required": true,
      "order": 0,
      "labels": { "en": { "label": "Phone number", "placeholder": "+33 6 12 34 56 78" } },
      "options": {}
    },
    {
      "id": "birth_date",
      "input": "date",
      "verification": null,
      "required": true,
      "order": 1,
      "labels": { "en": { "label": "Date of birth" }, "fr": { "label": "Date de naissance" } },
      "options": { "min_age": 18 }
    }
  ]
}

version is 0 while nothing has been published: the default flow (phone number and tag name) applies.

Collecting the values#

The flow tells your app which fields to ask. Once the user has filled the form, send the values to the API: the profile fields go in the body of Create a user or Update a user, validated against this same published flow (see User profiles and erasure), and the phone number is verified with the phone verification routes.

Rendering rules#

  • Render modules in array order. order repeats that position.
  • Pick the text for a module with this fallback chain: the user's locale, then default_locale, then en. en and default_locale are always present.
  • input tells you which control to show (phone, email, text, date, country, checkbox). verification: "code" means the value is verified by a one-time code.
  • Respect the module options: min_age for a birth date, allowed_countries for a country list, terms_url and privacy_url for the acceptance checkbox.
  • Ignore fields and modules you do not know: new modules can be added without a new API version.

Module reference#

Signup modules
Module idInputVerificationDescriptionOptions
phonephonecodePhone number, verified by a one-time code. Always present, enabled and required.—
emailemailnoneEmail address.—
tagnametextnonePublic tag name that other users can pay.—
first_nametextnoneFirst name.—
last_nametextnoneLast name.—
birth_datedatenoneDate of birth.min_age (0 to 120)
countrycountrynoneCountry of residence.allowed_countries (ISO 3166-1 alpha-2 codes)
referral_codetextnoneReferral code.—
terms_acceptancecheckboxnoneAcceptance of your terms and privacy policy.terms_url, privacy_url (https)

JSON Schema#

The response is described by this JSON Schema, which you can use to validate it or to generate types.

Show the JSON Schema
signup-config.json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://tilt-pay.com/schemas/signup-config.json",
  "title": "Tilt Pay public signup configuration (GET /v1/signup-config)",
  "description": "Describes the modules of a project's published signup flow. SDK UI components are generated from `modules` (already ordered, only enabled modules).",
  "type": "object",
  "required": [
    "schema_version",
    "version",
    "default_locale",
    "modules"
  ],
  "properties": {
    "schema_version": {
      "const": 1
    },
    "version": {
      "type": "integer",
      "minimum": 0,
      "description": "0 = default configuration (nothing published yet)."
    },
    "default_locale": {
      "enum": [
        "en",
        "fr",
        "es",
        "de",
        "it",
        "pt"
      ]
    },
    "modules": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "input",
          "verification",
          "required",
          "order",
          "labels",
          "options"
        ],
        "properties": {
          "id": {
            "enum": [
              "phone",
              "email",
              "tagname",
              "first_name",
              "last_name",
              "birth_date",
              "country",
              "referral_code",
              "terms_acceptance"
            ]
          },
          "input": {
            "enum": [
              "phone",
              "email",
              "text",
              "date",
              "country",
              "checkbox"
            ]
          },
          "verification": {
            "enum": [
              "code",
              null
            ],
            "description": "'code' = value verified by a one-time code (phone)."
          },
          "required": {
            "type": "boolean"
          },
          "order": {
            "type": "integer",
            "minimum": 0
          },
          "labels": {
            "type": "object",
            "propertyNames": {
              "enum": [
                "en",
                "fr",
                "es",
                "de",
                "it",
                "pt"
              ]
            },
            "additionalProperties": {
              "type": "object",
              "required": [
                "label"
              ],
              "properties": {
                "label": {
                  "type": "string",
                  "maxLength": 80
                },
                "placeholder": {
                  "type": "string",
                  "maxLength": 80
                },
                "help_text": {
                  "type": "string",
                  "maxLength": 200
                }
              },
              "additionalProperties": false
            },
            "description": "Always contains `en` and `default_locale`. Fall back to `default_locale`, then `en`."
          },
          "options": {
            "type": "object",
            "properties": {
              "min_age": {
                "type": "integer",
                "minimum": 0,
                "maximum": 120
              },
              "allowed_countries": {
                "type": "array",
                "items": {
                  "type": "string",
                  "pattern": "^[A-Z]{2}$"
                }
              },
              "terms_url": {
                "type": "string",
                "format": "uri"
              },
              "privacy_url": {
                "type": "string",
                "format": "uri"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "contains": {
        "type": "object",
        "properties": {
          "id": {
            "const": "phone"
          },
          "required": {
            "const": true
          }
        },
        "required": [
          "id",
          "required"
        ]
      },
      "minItems": 1
    }
  },
  "additionalProperties": false
}