## Collect Your Incode Credentials

You need three things from Incode to configure Tines:

- An API key (`*API_KEY*`)
- An integration ID (`*INTEGRATION_ID*`)
- An integration secret (`*INTEGRATION_SECRET*`)

To retrieve these values:

1. Open [Dashboard](https://dashboard.incode.com/) and log in.
2. Go to **Settings > API Keys** in the left menu.
3. Select **Create new API key**.
4. Enter a descriptive name such as `tines-integration`.
5. Copy the generated key. This is your `*API_KEY*`.
6. Go to **Integrations** in the left menu.
7. Select the integration you want to use or create a new one.
8. From the integration detail page, copy the **Integration ID** and **Integration Secret**. These are your `*INTEGRATION_ID*` and `*INTEGRATION_SECRET*`.

> 📘  
> ### **Note**  
> If you are using Incode's sandbox environment, your API base URL will be `https://demo-api-incode-id.incodesmile.com`. For production, use the base URL provided by your Incode Representative.

## Add Credentials to Tines

1. Go to Tines and click **Credentials** in the left menu.
2. Add `*API_KEY*` as a **Text Credential** named `incode_x_api_key`. Add `incodesmile.com` in the **Domains** field.
3. Add `*INTEGRATION_ID*` as a **Text Credential** named `incode_workforce_integrationid`. Leave **Domains** blank.
4. Add `*INTEGRATION_SECRET*` as a **Text Credential** named `incode_workforce_secret`. Leave **Domains** blank.

All three credentials are entered as **Text** credentials and will look like this in the Tines Credentials panel:

| Name | Type | Domains |
| --- | --- | --- |
| `incode_x_api_key` | Text | `incodesmile.com` |
| `incode_workforce_integrationid` | Text | — |
| `incode_workforce_secret` | Text | — |

## Set Up Tines Actions

The steps below configure Tines to:

1. Authenticate with the Incode API to get a session token.
2. Generate a personalized verification link for the customer.
3. Deliver that link to the customer.
4. Wait for a webhook from Incode when the user completes verification.
5. Validate the webhook and use the result.

### Authenticate with Incode

Before you can generate a verification link, the Incode API requires a short-lived session token obtained through a server-side authentication call. This token is used as the `x-auth-token` header in subsequent requests.

1. Drag the **HTTP Request** action into your story from the sidebar and configure it as follows:

- **Name**: `GetIncodeToken`
   - **URL**: `https://demo-api-incode-id.incodesmile.com/v1/integration/authorize/server`
   - **Content type**: JSON
   - **Method**: `POST`
   - **Headers:**
     ```text
     x-api-key: {user.CREDENTIAL.incode_x_api_key}
     ```
   - **Payload:**
     ```json
     {
       "integrationId": "CREDENTIAL.INCODE_WORKFORCE_INTEGRATIONID",
       "secret": "CREDENTIAL.INCODE_WORKFORCE_SECRET"
     }
     ```

In the **Editor** view on the right side of the Tines workspace, this looks like:

```json
{
  "url": "https://demo-api-incode-id.incodesmile.com/v1/integration/authorize/server",
  "content_type": "application_json",
  "method": "post",
  "headers": {
    "x-api-key": "CREDENTIAL.INCODE_X_API_KEY"
  },
  "payload": {
    "integrationId": "CREDENTIAL.INCODE_WORKFORCE_INTEGRATIONID",
    "secret": "CREDENTIAL.INCODE_WORKFORCE_SECRET"
  }
}
```

2. Select **Play** on this action. The events window should show a successful response from Incode:
   
```json
{
     "token": "eyJhbGci....",
     "expiresAt": 1714512000
}
```

The `token` field is the session token. It is short-lived, so this action should run at the beginning of each story run. Don't store it for reuse across separate executions.

### Generate a Verification Link

Now that you have a session token, you can generate a personalized, time-limited verification link for the end-user.

1. Drag another **HTTP Request** action into your story and configure it as follows:
   - **Name**: `GenerateVerificationLink`
   - **URL**: `https://demo-api-incode-id.incodesmile.com/v1/workforce/verification/candidate/generate-verification-link`
   - **Content type**: JSON
   - **Method**: `POST`
   - **Headers:**
     ```text
     x-auth-token: GETINCODETOKEN.BODY.TOKEN
     ```
   - **Payload:**
     ```json
     {
       "integrationID": "CREDENTIAL.INCODE_WORKFORCE_INTEGRATIONID",
       "secret": "CREDENTIAL.INCODE_WORKFORCE_SECRET",
       "loginHint": "USER_EMAIL",
       "loginHintType": "EMAIL",
       "validityMinutes": 4320,
       "redirectUrl": "https://your-company.com",
       "givenNames": "USER_FIRST_NAME",
       "lastName": "USER_LAST_NAME"
     }
     ```

2. Replace `USER_EMAIL`, `USER_FIRST_NAME`, and `USER_LAST_NAME` with the Tines variables from wherever you collect the user's information earlier in your story: for example, from a web form, a webhook payload, or a previous API call.

3. The `validityMinutes` field controls how long the verification link stays active. `4320` equals 72 hours, which is a sensible default for most workflows. Adjust this to suit your use case.

In the **Editor** view, this looks like:

```json
{
     "url": "https://demo-api-incode-id.incodesmile.com/v1/workforce/verification/candidate/generate-verification-link",
     "content_type": "application_json",
     "method": "post",
     "headers": {
       "x-auth-token": "GETINCODETOKEN.BODY.TOKEN"
     },
     "payload": {
       "integrationID": "CREDENTIAL.INCODE_WORKFORCE_INTEGRATIONID",
       "secret": "CREDENTIAL.INCODE_WORKFORCE_SECRET",
       "loginHint": "USER_EMAIL",
       "loginHintType": "EMAIL",
       "validityMinutes": 4320,
       "redirectUrl": "https://your-company.com",
       "givenNames": "USER_FIRST_NAME",
       "lastName": "USER_LAST_NAME"
     }
}
```

4. Select **Play** on this action. The response from Incode looks like:

```json
{
     "verificationLink": "https://verify.incode.com/x/acme/abcd1234xyz",
     "verificationTraceId": "f78ee334-79a8-4a5e-be4a-d728e226df64"
}
```

The two key fields are:

- `verificationLink`: The URL you will send to the customer so they can complete biometric verification.
- `verificationTraceId`: A unique identifier for this verification session. **Store this value.** You will use it later to match the Incode webhook callback to this specific verification request.

### Deliver the Verification Link

Tines offers many methods to deliver data to end-users. Any of them will work for delivering this link: email, Slack, SMS, or a redirect from a Tines page.

To demonstrate the flow, we use email delivery. If your story has already collected the user's email address from a form or upstream system, skip the form step.

**Collect the User's Email**

1. If you need to collect the user's details first, select **\+ / Tools** on the left of your Tines workspace.
2. Drag a **Page** object onto your workspace.
3. Name the page `Request Identity Verification`.
4. Add input fields for the user's email address, first name, and last name.

**Send the Email**

1. Drag the **Send Email** action from the sidebar onto your workspace and configure it as follows:
   - **Recipients**: `USER_EMAIL` (or `REQUEST_IDENTITY_VERIFICATION.BODY.EMAIL` if using a Tines form)
   - **Reply to**: Your team's support email address
   - **Sender name**: Your company or team name
   - **Subject**: `Your identity verification request from *COMPANY*`
   - **Body**: Write a message explaining the purpose of the verification. Include the link using the Tines variable `GENERATEVERIFICATIONLINK.BODY.VERIFICATIONLINK`. For example:

```undefined
     Hi USER_FIRST_NAME,

Please complete your identity verification by clicking the link below.
     The process takes less than 5 minutes and requires a government-issued
     photo ID and a quick facial scan.

Verify your identity: GENERATEVERIFICATIONLINK.BODY.VERIFICATIONLINK

This link expires in 72 hours. If you have any questions, reply to
     this email and our team will be happy to help.
     ```

2. Connect the actions in your story so they run in this order: `GetIncodeToken` → `GenerateVerificationLink` → `Send Email`.
3. To test the flow, run the story and confirm the email arrives with a working verification link.

### Set Up the Incode Webhook

Incode can POST a signed message to a pre-defined HTTP endpoint when an end-user completes or fails verification. This is how you receive the result back into your Tines story.

**Create the Webhook Action in Tines**

1. Go to your Tines story and drag a **Webhook Action** into your workspace.
2. Select it to edit.
3. Set **Allowed verbs** to `POST` only.
4. Select **Copy** next to the **Webhook URL** to copy it. This is the `*DELIVERY_URL*` you will register in Incode.

**Register the Webhook in Incode**

1. Open [Dashboard](https://dashboard.incode.com/) ​.
2. Go to **Configuration** \> **Webhooks**.
3. Select your integration and open the **Webhooks** tab.
4. Select **Add Webhook** and configure it as follows:

| Field | Value |
| --- | --- |
| Delivery URL | Paste the `*DELIVERY_URL*` you copied from Tines |
| Events | `verification.succeeded`, `verification.failed` |
| Enabled | Toggle on |

5. Save the webhook. Incode will now POST an event to your Tines story each time a user completes or fails a verification session on this integration.

**Name the Webhook Action**

Back in Tines, rename the Webhook Action to `IncodeStatusWebhook` to make it easy to reference in downstream actions.

### Validate the Webhook in Tines

When Incode posts a verification result to your Tines story, the webhook body looks like this:

```json
{
  "event_type": "verification.succeeded",
  "data": {
    "verification_trace_id": "f78ee334-79a8-4a5e-be4a-d728e226df64",
    "failure_reason": null,
    "ip": "203.0.113.42",
    "user_name": "Jane Smith",
    "latitude": 37.7749,
    "longitude": -122.4194
  }
}
```

The `verification_trace_id` in the callback matches the `verificationTraceId` you received when you generated the link. This is how you confirm that this callback belongs to the verification session you initiated.

**Create a Trigger Action**

1. Drag a **Trigger Action** into your story.
2. Configure a rule that checks the incoming `event_type` and passes only events for successfully completed verifications:

```json
{
     "rules": [
       {
         "type": "field==value",
         "value": "verification.succeeded",
         "path": "INCODESTATUSWEBHOOK.BODY.EVENT_TYPE"
       }
     ]
}
```

This ensures that the rest of your story only runs when verification succeeds. To handle failures separately, add a second Trigger Action with `
