Quickstart

A quick guide to getting TIKI up and running

Introduction

The vast majority of TIKI runs application-side, meaning it's a breeze to get set up and running locally. Now, before we get started you'll need a Publishing ID; get one for free by signing up at console.mytiki.com and creating a new project.

Project Setup

With a Publishing ID in hand you can start configuring TIKI. The instructions below will guide you through the process of cloning the Quickstart repository, creating a data offer, signing your first data license, and then finally grabbing the result on the backend

TIKI offers a variety of web and mobile Quickstart options, the popular options are listed below, but check the repository for the full list if you're looking for something specific.

😭

Can't find what you're looking for?

Open a new Issue in the Quickstart repository or ask for help on Discord —we're always excited to get docs up for more platforms.

Enough talk. Let's get to work —clone the repo and open your variant of choice.

For example:

git clone https://github.com/tiki/quickstart.git
cd quickstart/web/javascript

Adding TIKI

With the repo cloned, you'll find a very much empty hello world-esq project waiting for you.

Note: If you get stuck, check the README.md file in each folder for briefer but more specific individual implementation instructions.

Ok, let's add TIKI.

<!-- add to the bottom of your body tag -->
<!-- check http://npmjs.com/package/@mytiki/tiki-sdk-js for the latest version -->
<script src="https://unpkg.com/@mytiki/[email protected]/dist/index.js"></script>
npm install @mytiki/tiki-sdk-js
Add the Swift Package repository: `https://github.com/tiki/tiki-sdk-ios`
implementation 'com.mytiki:tiki-sdk-android:2.1.2'
flutter pub add tiki_sdk_flutter

Dope. On to the good stuff.

Creating an Offer.

In the spirit of keeping this Quickstart... quick, we're going to skip styling the Pre-built UI theme. It's crazy easy, just follow our Pre-built UI guide.

Alright, let's go 1-by-1.

1. Use the config builder to initialize an empty offer object

window.TikiSdk.config()
  .offer
init() {
  try? TikiSdk.config()
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
}
void main() async {
  await TikiSdk.config()
    .offer
}

2. Set a Pointer Record (ptr)

Get a random UUID here. Normally in production you'd use a foreign key of sorts; read more about Selecting a Pointer Record.

window.TikiSdk.config()
  .offer
    .ptr('3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9')
init() {
  try? TikiSdk.config()
        .offer
            .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
      .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
}
void main() async {
  await TikiSdk.config()
    .offer
        .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
} 

3. Set a short, user friendly description of the offer

It might be something like Trade your IDFA (kind of like a serial # for your phone) for a discount off your next purchase.

window.TikiSdk.config()
  .offer
    .ptr('3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9')
    .description("I can't wait to tell people about TIKI")
init() {
  try? TikiSdk.config()
        .offer
            .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
            .description("I can't wait to tell people about TIKI")
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
      .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
      .description("I can't wait to tell people about TIKI")
}
void main() async {
  await TikiSdk.config()
    .offer
        .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
        .description("I can't wait to tell people about TIKI")
} 

4. Define our use case

There are 2 parts, specific metadata records about each use case, and then 3 pretty bullets to help explain in normal human, not data nerd words, wtf is actually going on.

Take ad attribution for example. Your metadata field would be LicenseUsecase.attribution but your bullet might read Insights into how our ads perform. Each bullet includes an additional flag isUsed which sets either a ✔︎ or X based on if it's used or not —it's often equally helpful for users to understand what you won't do as well as what you will do with their data.

window.TikiSdk.config()
  .offer
    .ptr('3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9')
    .description("I can't wait to tell people about TIKI")
    .use({ usecases:[TikiSdk.LicenseUsecase.attribution()] })
    .bullet({ text: 'Learn how our ads perform', isUsed: true })
    .bullet({ text: 'Reach you on other platforms', isUsed: false })
    .bullet({ text: 'Sold to other companies', isUsed: false })
init() {
  try? TikiSdk.config()
        .offer
            .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
            .description("I can't wait to tell people about TIKI")
            .use(usecases: [LicenseUsecase.attribution])
            .bullet(text: "Learn how our ads perform ", isUsed: true)
            .bullet(text: "Reach you on other platforms", isUsed: false)
            .bullet(text: "Sold to other companies", isUsed: false)
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
      .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
      .description("I can't wait to tell people about TIKI")
      .use(listOf(LicenseUsecase.ATTRIBUTION))
      .bullet("Learn how our ads perform ", true)
      .bullet("Reach you on other platforms", false)
      .bullet("Sold to other companies", false)
}
void main() async {
  await TikiSdk.config()
    .offer
        .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
        .description("I can't wait to tell people about TIKI")
        .use([LicenseUsecase.attribution()])
        .bullet("Learn how our ads perform ", true)
        .bullet("Reach you on other platforms", false)
        .bullet("Sold to other companies", false)
} 

Almost, there. Just a couple more parameters and then we can see it in action.

5. Add a data tag

Tags describe the underly data represented by the license, the data pointer record... points at. These are super handy when searching for, and bulk enforcing licenses. Read more about the supported tags here, but for now let's use the custom tag quickstart. We'll use this in a later step when grabbing your licenses from the API.

window.TikiSdk.config()
  .offer
    .ptr('3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9')
    .description("I can't wait to tell people about TIKI")
    .use({ usecases:[TikiSdk.LicenseUsecase.attribution()] })
    .bullet({ text: 'Learn how our ads perform', isUsed: true })
    .bullet({ text: 'Reach you on other platforms', isUsed: false })
    .bullet({ text: 'Sold to other companies', isUsed: false })
    .tag(TikiSdk.TitleTag.custom("quickstart"))
init() {
  try? TikiSdk.config()
        .offer
            .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
            .description("I can't wait to tell people about TIKI")
            .use(usecases: [LicenseUsecase.attribution])
            .bullet(text: "Learn how our ads perform ", isUsed: true)
            .bullet(text: "Reach you on other platforms", isUsed: false)
            .bullet(text: "Sold to other companies", isUsed: false)
            .tag(TitleTag("quickstart"))
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
      .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
      .description("I can't wait to tell people about TIKI")
      .use(listOf(LicenseUsecase.ATTRIBUTION))
      .bullet("Learn how our ads perform ", true)
      .bullet("Reach you on other platforms", false)
      .bullet("Sold to other companies", false)
      .tag(TitleTag("quickstart"))
}
void main() async {
  await TikiSdk.config()
    .offer
        .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
        .description("I can't wait to tell people about TIKI")
        .use([LicenseUsecase.attribution()])
        .bullet("Learn how our ads perform ", true)
        .bullet("Reach you on other platforms", false)
        .bullet("Sold to other companies", false)
        .tag(TitleTag.custom("quickstart"))
} 

Finally we add our legal terms and reward graphic

We've included examples of these two files (terms.md and reward.png) so you don't need to create your own (just yet). You'll want and need to for production; learn about including t's and c's and crafting a reward image.

window.TikiSdk.config()
  .offer
    .ptr('3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9')
    .description("I can't wait to tell people about TIKI")
    .use({ usecases:[TikiSdk.LicenseUsecase.attribution()] })
    .bullet({ text: 'Learn how our ads perform', isUsed: true })
    .bullet({ text: 'Reach you on other platforms', isUsed: false })
    .bullet({ text: 'Sold to other companies', isUsed: false })
    .tag(TikiSdk.TitleTag.custom("quickstart"))
    .reward('reward.png')
    .terms('terms.md')
init() {
  try? TikiSdk.config()
        .offer
            .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
            .description("I can't wait to tell people about TIKI")
            .use(usecases: [LicenseUsecase.attribution])
            .bullet(text: "Learn how our ads perform ", isUsed: true)
            .bullet(text: "Reach you on other platforms", isUsed: false)
            .bullet(text: "Sold to other companies", isUsed: false)
            .tag(TitleTag("quickstart"))
            .reward("reward")
            .terms("terms.md")
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
      .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
      .description("I can't wait to tell people about TIKI")
      .use(listOf(LicenseUsecase.ATTRIBUTION))
      .bullet("Learn how our ads perform ", true)
      .bullet("Reach you on other platforms", false)
      .bullet("Sold to other companies", false)
      .tag(TitleTag("quickstart"))
      .reward(ResourcesCompat.getDrawable(resources, R.drawable.reward, null)!!)
      .terms(this,"terms.md")
}
void main() async {
  await TikiSdk.config()
    .offer
        .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
        .description("I can't wait to tell people about TIKI")
        .use([LicenseUsecase.attribution()])
        .bullet("Learn how our ads perform ", true)
        .bullet("Reach you on other platforms", false)
        .bullet("Sold to other companies", false)
        .tag(TitleTag.custom("quickstart"))
        .reward("assets/images/reward.png")
        .terms("assets/terms.md")
} 

Boom and we're configured! All that's left is to call initialize.

You need your Publishing ID from earlier. You'll also set a user id —this is your user's id in your system! It enables easy license querying, cross-device syncing (phone + tablet), and helps avoid duplicate/conflicting contracts. For our example, just pick a fake id; make up something funny or grab another UUID.

window.TikiSdk.config()
  .offer
    .ptr('3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9')
    .description("I can't wait to tell people about TIKI")
    .use({ usecases:[TikiSdk.LicenseUsecase.attribution()] })
    .bullet({ text: 'Learn how our ads perform', isUsed: true })
    .bullet({ text: 'Reach you on other platforms', isUsed: false })
    .bullet({ text: 'Sold to other companies', isUsed: false })
    .tag(TikiSdk.TitleTag.custom("quickstart"))
    .reward('reward.png')
    .terms('terms.md')
    .add()
  .initialize('PUBLISHING ID', 'muppet420')
init() {
  try? TikiSdk.config()
        .offer
            .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
            .description("I can't wait to tell people about TIKI")
            .use(usecases: [LicenseUsecase.attribution])
            .bullet(text: "Learn how our ads perform ", isUsed: true)
            .bullet(text: "Reach you on other platforms", isUsed: false)
            .bullet(text: "Sold to other companies", isUsed: false)
            .tag(TitleTag("quickstart"))
            .reward("reward")
            .terms("terms.md")
            .add()
        .initialize(publishingId: "PUBLISHING ID", id: "muppet420")
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
      .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
      .description("I can't wait to tell people about TIKI")
      .use(listOf(LicenseUsecase.ATTRIBUTION))
      .bullet("Learn how our ads perform ", true)
      .bullet("Reach you on other platforms", false)
      .bullet("Sold to other companies", false)
      .tag(TitleTag("quickstart"))
      .reward(ResourcesCompat.getDrawable(resources, R.drawable.reward, null)!!)
      .terms(this,"terms.md")
      .and()
    .initialize(this, "PUBLISHING ID", "muppet420")
}
void main() async {
  await TikiSdk.config()
    .offer
        .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
        .description("I can't wait to tell people about TIKI")
        .use([LicenseUsecase.attribution()])
        .bullet("Learn how our ads perform ", true)
        .bullet("Reach you on other platforms", false)
        .bullet("Sold to other companies", false)
        .tag(TitleTag.custom("quickstart"))
        .reward("assets/images/reward.png")
        .terms("assets/terms.md")
        .add()
    .initialize("PUBLISHING ID", "muppet420");
} 

Displaying the Offer

Yahtzee. Now let's display our offer —all you have to do is call TikiSdk.present(). I know, it seems almost too-easy and anti-climactic. We'll add a simple button to our project to call present().

<div class="welcome">
  <a href="https://mytiki.com">
    <img alt="TIKI" src="https://cdn.mytiki.com/assets/icon-logo.svg">
  </a>
    <h1>Let&#39;s do this shit</h1>
  <button onclick="TikiSdk.present()">Show Offer</button>
</div>
struct ContentView: View {
    var body: some View {
        VStack {
            Image("iconLogo").imageScale(.large)
            Text("Let's do this shit").padding(.bottom, 24)
            Button(action: {
                do{
                    try TikiSdk.present()
                }catch{
                    print(error)
                }
            }) {
                Text("Show Offer")
            }
            .foregroundColor(Color(red: 1, green: 0.722, blue: 0.133))
            .padding(12)
            .background(Color(red: 0.11, green: 0, blue: 0))
            .cornerRadius(8)
        }
    }
}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  TikiSdk
    .offer
      .ptr("3332bd1b-7b0a-4b0f-a4e1-7fb28d3524f9")
      .description("I can't wait to tell people about TIKI")
      .use(listOf(LicenseUsecase.ATTRIBUTION))
      .bullet("Learn how our ads perform ", true)
      .bullet("Reach you on other platforms", false)
      .bullet("Sold to other companies", false)
      .tag(TitleTag("quickstart"))
      .reward(ResourcesCompat.getDrawable(resources, R.drawable.reward, null)!!)
      .terms(this,"terms.md")
      .and()
    .init(this, "f3dbd181-1273-4be7-8a56-a9d258feccda", "muppet420"){
      setContentView(R.layout.activity_main)
      findViewById<Button>(R.id.start).setOnClickListener {
        TikiSdk.present(this)
      }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center|center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
            android:layout_width="wrap_content"
            android:layout_height="60dp"
            android:src="@drawable/icon_logo"
    />

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Let's do this shit"
            android:textColor="#1C0000"
            android:layout_marginVertical="5dp"
    />

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Offer"
        android:background="#1C0000"
        android:textColor="#FFB822"
        android:padding="10dp"
        android:layout_marginTop="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Center(
        child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
          Image.asset("assets/images/doc-logo.png"),
          const Padding(
              padding: EdgeInsets.symmetric(vertical: 10.0),
              child: Text("Let's do this shit")),
          ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor:
                    const Color(0xFF1C0000), // background (button) color
                foregroundColor:
                    const Color(0xFFFFCC33), // foreground (text) color
              ),
              onPressed: () => TikiSdk.present(context),
              child: const Text("Show Offer"))
        ]));
  }
}

You should see something roughly like this:


Go ahead and click, I'm In and accept the fake Terms & Conditions. When you do so, behind the scenes the SDK creates and digitally signs the immutable Title and License Records on behalf of you the user, and also you in this case, the company.

Get your newly created license from the API

First you'll need an API Key (they're also free), just open back up the TIKI Console. Open your project and under Private Keys click +.

Copy down both the ID and especially the secret (you won't be able to see it again).

Exchange your API Key for an Access Token

Open up your Terminal/Command Prompt and run:

curl -G --request POST \
     --url 'https://mytiki.com/api/authorize' \
     --header 'Content-Type: application/x-www-form-urlencoded' \
     --header 'accept: application/json' \
     --data-urlencode 'grant_type=client_credentials' \
     --data-urlencode 'scope=index' \
     --data-urlencode 'client_id=<API KEY ID>' \
     --data-urlencode 'client_secret=<API KEY SECRET>' \
     

In the response, copy the access_token field. It's a JWT so don't be surprised if it's on the long end. Ready? One last request.

Retrieving the license record

We're going to use that custom tag (quickstart) from earlier to locate your license record.

You'll notice the response from the List Licenses API is missing a few details. It returns a compressed record set, meant for use in high-volume production environments where your if statements don't need things like each word in the legal contract.

curl --request POST \
     --url 'https://mytiki.com/api/license/list?maxResults=100' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <ACCESS TOKEN>' \
     --header 'content-type: application/json' \
     --data '
{
  "tags": [
    "custom:quickstart"
  ]
}
'

You should get back something like:

{
  "approxResults":1,
  "results":[
    {
      "id":"cu4yNsQCA9I7s8UgCi0M-XWw5wzdZT_s1bz9mdCaQ4M",
      "ptr":"FJGgbIVAqeMhUMPBk7zQ/RT4Qwkywqz2NQfKCpV3TvQ=",
      "tags":[
        "custom:quickstart"
      ],
      "uses":[
        {
          "usecase":"attribution"
        }
      ]
    }
  ]
}

Want to see the full License and Title records?

Use the id field from the List Licenses response and call Get License. Then grab the title field from the Get License response and call Get Title.




What’s Next

Damn you're good! You'll be into production in no time.