Skip to main content

Tutorial: Your first iGUIDE

Learn how to create an iGUIDE, upload Stitch Data and check processing status using the Portal API.

Time to complete: ~10 minutes

What you'll learn:

  • How to authenticate with the Portal API
  • How to create a new iGUIDE
  • How to upload Stitch Data to S3
  • How to poll for processing completion

Prerequisites

Before you begin, you need:

  • App ID and Access Token (see below for how to create them)
  • A Stitch TAR file (for this tutorial, we'll assume you have property.stitch.tar)
  • curl or any HTTP client

Getting your API credentials

You can self-serve your API credentials via the API Management page in the iGUIDE Portal:

  1. Log in to the iGUIDE Portal
  2. Navigate to SettingsAPI Management
  3. Click Create API Token
  4. Provide a name and select the required scopes (for this tutorial, you'll need iguide.tasks and iguide.rw)
  5. Copy the Token ID (this is your $APP_ID) and Token Value (this is your $APP_TOKEN)
Save your token

The token value is only shown once when created. Make sure to save it securely—you won't be able to retrieve it later. If you lose it, you'll need to rotate or create a new token.

OAuth vs API token

For getting started quickly, we recommend using API Tokens as shown above. They're simpler and faster to set up.

If you need full OAuth 2.0 authentication with authorization flows, you can create an OAuth App instead. See our Authentication Guide for complete details on both methods.

Step 1: Set up your environment

First, let's store your credentials as environment variables for easy reuse:

export APP_ID="your-app-id-here"
export APP_TOKEN="your-access-token-here"

All Portal API requests require these two authentication headers:

  • X-Plntr-App-Id: Your application UUID
  • X-Plntr-App-Token: Your JWT access token

Step 2: Test your authentication

Before creating an iGUIDE, verify your credentials are working:

curl -X POST https://youriguide.com/api/v1/integrations/test \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN"

Expected response:

{
"appId": "your-app-id-here"
}

If you receive a 401 Unauthorized error, double-check your credentials.

Step 3: Create your first iGUIDE

Now let's create a new iGUIDE. You need to provide three required fields:

  • type: The iGUIDE package type (e.g., "standard", "premium", "radix")
  • industry: The property type (e.g., "residential", "commercial")
  • address: Complete property address
curl -X POST https://youriguide.com/api/v1/iguides \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN" \
-d '{
"type": "standard",
"industry": "residential",
"address": {
"country": "CA",
"provinceState": "ON",
"city": "Waterloo",
"postalCode": "N2L 3G1",
"streetName": "University Ave",
"streetNumber": "200"
}
}'

Response:

{
"id": "ig12345",
"alias": "200_university_ave_waterloo_on",
"workOrderId": "Z1T9",
"defaultViewId": "v123"
}
Save these IDs

Important: Save the id and workOrderId from this response—you'll need them for uploading data.

export IGUIDE_ID="ig12345"
export WORK_ORDER_ID="Z1T9"

What just happened?

  • An iGUIDE was created with a unique ID (ig12345)
  • A work order was automatically created to track processing (Z1T9)
  • A default view was created for displaying the final iGUIDE (v123)
  • An alias was generated from the address for friendly URLs

Step 4: Get S3 upload credentials

To upload your Stitch Data, you need temporary AWS credentials. The Portal API uses STS federation tokens (not presigned URLs) that are valid for 24 hours.

curl -X POST https://youriguide.com/api/v1/iguides/$IGUIDE_ID/workOrders/$WORK_ORDER_ID/stitchData \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN" \
-d '{
"filename": "property.stitch.tar",
"filesize": 55395840
}'
tip

The filesize value must be the exact size of the file in bytes. Use stat filename.tar to get it.

Response:

{
"id": "4MN",
"uploadPermit": {
"region": "us-east-1",
"bucket": "iguides.plntr.ca",
"key": "stitch-data/4MN/original.tar",
"accessKeyId": "ASIAXXX...",
"secretAccessKey": "xxx...",
"sessionToken": "FwoGZXIvYXdz..."
},
"uploadToken": "eyJhbGciOiJIUzI1NiIs..."
}
Credential lifetime

These temporary credentials expire after 24 hours. If your upload takes longer, request new credentials. For a deep dive on this pattern, see S3 Upload Pattern.

Step 5: Upload to S3

Now use the AWS credentials to upload your Stitch TAR file directly to S3:

# Save the credentials from the upload permit response
export AWS_ACCESS_KEY_ID="ASIAXXX..."
export AWS_SECRET_ACCESS_KEY="xxx..."
export AWS_SESSION_TOKEN="FwoGZXIvYXdz..."
export S3_BUCKET="iguides.plntr.ca"
export S3_KEY="stitch-data/4MN/original.tar"
export STITCH_DATA_ID="4MN"
export UPLOAD_TOKEN="eyJhbGciOiJIUzI1NiIs..."

# Upload using AWS CLI
aws s3 cp property.stitch.tar s3://$S3_BUCKET/$S3_KEY \
--acl bucket-owner-full-control \
--region us-east-1
Production recommendation

For production applications, use an official AWS SDK (JavaScript, Python, Go, etc.) to handle S3 uploads. The SDKs handle authentication, retries and multipart uploads automatically. See S3 Upload Pattern for examples in multiple languages.

Expected output:

upload: ./property.stitch.tar to s3://iguides.plntr.ca/stitch-data/$STITCH_DATA_ID/original.tar

Step 6: Trigger processing

After uploading to S3, tell the Portal API to process the uploaded file. Pass the stitchDataId in the path and the uploadToken as a query parameter:

curl -X POST "https://youriguide.com/api/v1/iguides/$IGUIDE_ID/workOrders/$WORK_ORDER_ID/stitchData/$STITCH_DATA_ID/process?uploadToken=$UPLOAD_TOKEN" \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN"

Response:

{
"jid": "abc123",
"jidEnqueuedAt": "2025-02-18T19:30:00Z"
}

This enqueues an asynchronous processing job. The iGUIDE processing pipeline typically takes 15-30 minutes depending on the size and complexity.

tip

The stitchDataId is found in the output of the S3 upload.

Step 7: Poll for completion

To check if your iGUIDE is ready, poll the work order status:

curl https://youriguide.com/api/v1/iguides/$IGUIDE_ID/workOrders/$WORK_ORDER_ID \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN"

Response (processing):

{
"id": "Z1T9",
"status": "pending_draft",
"iguideId": "ig12345",
"iguideType": "standard"
}

Response (completed):

{
"id": "Z1T9",
"status": "done",
"iguideId": "ig12345",
"iguideType": "standard"
}
Polling best practices
  • Check expected processing times* for your iGUIDE Package Type before polling
  • Poll every 30-60 seconds to check status
  • Set a reasonable timeout (e.g., 1 hour)
  • Better yet: Use webhooks to get notified automatically when processing completes

Work order status values:

  • empty: Initial state, no data uploaded yet
  • pending_draft, pending_qa, pending_publish, exception: Work order is being processed
  • on_hold: Queued behind another active work order
  • done: iGUIDE is ready to view
  • cancelled: Work order was cancelled
  • rejected: Processing rejected due to data quality issues

Step 8: Access your iGUIDE

Once the work order status is done, your iGUIDE is ready! You can:

View in the Portal:

https://manage.youriguide.com/iguides/edit/ig12345

Embed in your application:

<iframe src="https://my.youriguide.com/v123" width="100%" height="600px"></iframe>

Download deliverables:

  • Floor plans (DWG, RVT)
  • Measurement data (ESX)
  • Check the API Reference for download endpoints

Complete script

Here's the complete workflow in a single script:

#!/bin/bash
set -e

# Configuration
export APP_ID="your-app-id"
export APP_TOKEN="your-access-token"
STITCH_FILE="property.stitch.tar"

# 1. Test authentication
echo "Testing authentication..."
curl -X POST https://youriguide.com/api/v1/integrations/test \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN"

# 2. Create iGUIDE
echo "Creating iGUIDE..."
CREATE_RESPONSE=$(curl -s -X POST https://youriguide.com/api/v1/iguides \
-H "Content-Type: application/json" \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN" \
-d '{
"type": "standard",
"industry": "residential",
"address": {
"country": "CA",
"provinceState": "ON",
"city": "Waterloo",
"postalCode": "N2L 3G1",
"streetName": "University Ave",
"streetNumber": "200"
}
}')

IGUIDE_ID=$(echo $CREATE_RESPONSE | jq -r '.id')
WORK_ORDER_ID=$(echo $CREATE_RESPONSE | jq -r '.workOrderId')

echo "Created iGUIDE: $IGUIDE_ID with Work Order: $WORK_ORDER_ID"

# 3. Get upload permit
echo "Getting S3 upload credentials..."
UPLOAD_RESPONSE=$(curl -s -X POST https://youriguide.com/api/v1/iguides/$IGUIDE_ID/workOrders/$WORK_ORDER_ID/stitchData \
-H "Content-Type: application/json" \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN" \
-d "{
\"filename\": \"$STITCH_FILE\",
\"filesize\": $(stat -c%s "$STITCH_FILE")
}")

STITCH_DATA_ID=$(echo $UPLOAD_RESPONSE | jq -r '.id')
UPLOAD_TOKEN=$(echo $UPLOAD_RESPONSE | jq -r '.uploadToken')
export AWS_ACCESS_KEY_ID=$(echo $UPLOAD_RESPONSE | jq -r '.uploadPermit.accessKeyId')
export AWS_SECRET_ACCESS_KEY=$(echo $UPLOAD_RESPONSE | jq -r '.uploadPermit.secretAccessKey')
export AWS_SESSION_TOKEN=$(echo $UPLOAD_RESPONSE | jq -r '.uploadPermit.sessionToken')
S3_BUCKET=$(echo $UPLOAD_RESPONSE | jq -r '.uploadPermit.bucket')
S3_KEY=$(echo $UPLOAD_RESPONSE | jq -r '.uploadPermit.key')

# 4. Upload to S3
echo "Uploading to S3..."
aws s3 cp $STITCH_FILE s3://$S3_BUCKET/$S3_KEY \
--acl bucket-owner-full-control \
--region us-east-1

# 5. Trigger processing
echo "Triggering processing..."
curl -s -X POST "https://youriguide.com/api/v1/iguides/$IGUIDE_ID/workOrders/$WORK_ORDER_ID/stitchData/$STITCH_DATA_ID/process?uploadToken=$UPLOAD_TOKEN" \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN"

# 6. Poll for completion
echo "Polling for completion..."
while true; do
STATUS_RESPONSE=$(curl -s https://youriguide.com/api/v1/iguides/$IGUIDE_ID/workOrders/$WORK_ORDER_ID \
-H "X-Plntr-App-Id: $APP_ID" \
-H "X-Plntr-App-Token: $APP_TOKEN")

STATUS=$(echo $STATUS_RESPONSE | jq -r '.status')
echo "Current status: $STATUS"

if [ "$STATUS" = "done" ]; then
echo "iGUIDE is ready! View at: https://youriguide.com/iguides/$IGUIDE_ID"
break
elif [ "$STATUS" = "rejected" ] || [ "$STATUS" = "cancelled" ]; then
echo "Processing $STATUS!"
exit 1
fi

sleep 30
done

Next steps

Congratulations! You've successfully created your first iGUIDE using the Portal API. Here's what to explore next:

Troubleshooting

Authentication fails (401)

Problem: {"code": "unauthenticated"}

Solutions:

  • Verify your App ID and Access Token are correct
  • Check for extra whitespace in your credentials
  • Ensure headers use exact names: X-Plntr-App-Id and X-Plntr-App-Token

iGUIDE creation fails (400)

Problem: {"code": "invalid_argument"}

Solutions:

  • Verify all required fields are provided: type, industry, address
  • Check that the address is complete and valid
  • Ensure type is one of: standard, premium, radix, photos
  • Ensure industry is one of: residential, commercial, irc, aec

S3 upload fails (403)

Problem: Access Denied when uploading to S3

Solutions:

  • Verify you're using all three credentials: accessKeyId, secretAccessKey and sessionToken
  • Ensure you're including --acl bucket-owner-full-control on the upload
  • Check if credentials expired (24-hour lifetime for Stitch Data)
  • Ensure you're uploading to the exact bucket and key from the uploadPermit response
  • Request new credentials if needed

Work order stays in processing

Problem: Status remains in a processing state (pending_draft, pending_qa, etc.) for longer than expected.

Solutions:

  • Check the file was uploaded correctly to S3
  • Verify you called the /process endpoint after uploading
  • Contact support if the issue persists—there may be a processing error

Rate limiting (429)

Problem: {"code": "resource_exhausted"}

Solutions:

  • Check the X-RateLimit-* response headers for your current limits
  • Reduce request frequency
  • Wait for the Retry-After duration before retrying
  • Consider using webhooks instead of aggressive polling