Just Scan It REST API: The Complete Developer Guide
Table of Contents
Introduction
The Just Scan It REST API gives you full programmatic access to your QR codes, redirect rules, landing pages, and scan analytics. Whether you're building an internal dashboard, automating QR code creation from your CRM, or pulling scan data into your own analytics pipeline — the API has you covered.
Base URL:
https://justscanit.com/api/v1
All endpoints return JSON and require authentication.
Authentication
The API uses OAuth 2.0 Personal Access Tokens via Laravel Passport.
Getting your token
- Log in to your Just Scan It dashboard
- Navigate to API Keys in the sidebar
- Click Create new token
- Select the scopes you need (see below)
- Copy the token — it will only be shown once
Using your token
Include the token in every request as a Bearer token:
Authorization: Bearer YOUR_TOKEN_HERE
Available scopes
| Scope | Description |
|---|---|
read |
View QR codes, landing pages, and user info |
write |
Create and update QR codes, redirect rules, and landing pages |
delete |
Delete QR codes, redirect rules, and landing pages |
scans:read |
View scan analytics and summaries |
You only need to request the scopes your integration actually uses. A read-only dashboard? Just request read and scans:read.
Requirements
- You must have an active subscription or credits on your account to access the API.
- API requests are scoped to your current team context automatically.
Pagination
All list endpoints return paginated results. The default page size is 15 items per page, with a maximum of 100.
GET /api/v1/qr-codes?per_page=25&page=2
Paginated responses include a meta object with current_page, last_page, per_page, and total.
QR Codes
QR codes are the heart of Just Scan It. Each QR code has a unique slug and a public redirect URL.
List QR codes
GET /api/v1/qr-codes
Scope: read
Query parameters:
| Parameter | Type | Description |
|---|---|---|
filter[type] |
string | Filter by static or dynamic |
filter[is_active] |
boolean | Filter by active status |
filter[content_type] |
string | Filter by url, file, landing_page, or landing_page_block |
sort |
string | Sort field. Prefix with - for descending. Options: created_at, name, updated_at |
per_page |
integer | Results per page (1–100, default 15) |
Example request:
curl -X GET "https://justscanit.com/api/v1/qr-codes?filter[type]=dynamic&sort=-created_at" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Example response:
{
"data": [
{
"id": 1,
"name": "Spring Campaign",
"slug": "spring-2026",
"type": "dynamic",
"target_url": "https://example.com/spring",
"fallback_url": null,
"is_active": true,
"content_type": "url",
"expires_at": null,
"licensed_until": "2027-04-01T00:00:00Z",
"auto_renew": true,
"public_url": "https://justscanit.com/r/spring-2026",
"options": {},
"created_at": "2026-03-15T10:30:00Z",
"updated_at": "2026-03-15T10:30:00Z"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 1
}
}
Get a single QR code
GET /api/v1/qr-codes/{id}
Scope: read
Returns the full QR code object including its redirect rules and associated landing page (if any).
Create a QR code
POST /api/v1/qr-codes
Scope: write
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | A descriptive name for the QR code |
type |
string | Yes | static or dynamic |
target_url |
string | Conditional | Required when content_type is url |
content_type |
string | No | url (default), file, landing_page, or landing_page_block |
fallback_url |
string | No | Fallback URL when redirect rules don't match |
is_active |
boolean | No | Whether the QR code is active (default: true) |
auto_renew |
boolean | No | Automatically renew with credits when license expires |
options |
object | No | Visual customization options (colors, logo, etc.) |
Example request:
curl -X POST "https://justscanit.com/api/v1/qr-codes" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "Summer Sale QR",
"type": "dynamic",
"target_url": "https://shop.example.com/summer",
"fallback_url": "https://shop.example.com",
"auto_renew": true
}'
Update a QR code
PUT /api/v1/qr-codes/{id}
Scope: write
Accepts the same body parameters as creation. Only include the fields you want to change.
Delete a QR code
DELETE /api/v1/qr-codes/{id}
Scope: delete
Returns 204 No Content on success.
Redirect Rules
Redirect rules let you route scans to different URLs based on device type, country, time of day, or day of the week. Rules are evaluated by priority — the first matching rule wins.
List redirect rules
GET /api/v1/qr-codes/{qrCodeId}/rules
Scope: read
Create a redirect rule
POST /api/v1/qr-codes/{qrCodeId}/rules
Scope: write
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | The destination URL for this rule |
device |
string | No | Target device: ios, android, windows, mac, linux, etc. |
country_code |
string | No | ISO 3166-1 alpha-2 country code (e.g. NL, US, DE) |
start_at |
datetime | No | Rule becomes active at this time |
end_at |
datetime | No | Rule expires at this time |
days_of_week |
array | No | Array of days: ["monday", "tuesday", ...] |
priority |
integer | No | Lower number = higher priority (default: 0) |
weight |
integer | No | For weighted random distribution among same-priority rules |
is_active |
boolean | No | Whether the rule is active (default: true) |
Example — send iOS users to the App Store:
curl -X POST "https://justscanit.com/api/v1/qr-codes/1/rules" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://apps.apple.com/app/your-app/id123456",
"device": "ios",
"priority": 1
}'
Example — weekday-only promotion for German users:
curl -X POST "https://justscanit.com/api/v1/qr-codes/1/rules" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://shop.example.com/de/weekday-deal",
"country_code": "DE",
"days_of_week": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"start_at": "2026-04-01T08:00:00Z",
"end_at": "2026-06-30T22:00:00Z",
"priority": 2
}'
Update a redirect rule
PUT /api/v1/qr-codes/{qrCodeId}/rules/{ruleId}
Scope: write
Delete a redirect rule
DELETE /api/v1/qr-codes/{qrCodeId}/rules/{ruleId}
Scope: delete
Scan Analytics
Pull detailed scan data or quick summaries for any QR code.
List scans
GET /api/v1/qr-codes/{qrCodeId}/scans
Scope: scans:read
Returns a paginated list of individual scans with device, country, referrer, UTM parameters, and timestamp data.
Example response:
{
"data": [
{
"id": 42,
"device": "ios",
"country_code": "NL",
"referer": "https://instagram.com",
"utm_source": "instagram",
"utm_medium": "social",
"utm_campaign": "spring_launch",
"resolved_url": "https://shop.example.com/spring",
"created_at": "2026-03-20T14:22:00Z"
}
]
}
Scan summary
GET /api/v1/qr-codes/{qrCodeId}/scans/summary
Scope: scans:read
Returns aggregated statistics: total scans, scans this month, top devices, top countries, and more. Perfect for dashboards and reports.
Landing Pages
Create and manage link-in-bio style landing pages that can be linked to QR codes.
List landing pages
GET /api/v1/landing-pages
Scope: read
Get a single landing page
GET /api/v1/landing-pages/{id}
Scope: read
Create a landing page
POST /api/v1/landing-pages
Scope: write
Body parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
title |
string | Yes | Page title |
description |
string | No | Page description for SEO |
preset |
string | No | Theme preset: minimal, dark, colorful, corporate, nature, neon, pastel |
Update a landing page
PUT /api/v1/landing-pages/{id}
Scope: write
Delete a landing page
DELETE /api/v1/landing-pages/{id}
Scope: delete
User Info
GET /api/v1/user
Scope: read
Returns the authenticated user's profile, including current plan, credits balance, and team context.
Error Handling
The API uses standard HTTP status codes:
| Code | Meaning |
|---|---|
200 |
Success |
201 |
Created |
204 |
Deleted (no content) |
401 |
Unauthorized — invalid or missing token |
402 |
Payment required — no active subscription or credits |
403 |
Forbidden — insufficient scope or permissions |
404 |
Resource not found |
422 |
Validation error — check the errors object in the response |
429 |
Rate limited — too many requests |
Validation error example:
{
"message": "The name field is required.",
"errors": {
"name": ["The name field is required."]
}
}
Rate Limiting
API requests are rate-limited to protect the platform. If you hit the limit, you'll receive a 429 response with a Retry-After header indicating how many seconds to wait.
Tips & Best Practices
- Use the narrowest scope possible. A reporting integration only needs
readandscans:read. - Store tokens securely. Treat API tokens like passwords — never commit them to source control.
- Use pagination. Don't try to fetch all records at once. Use
per_pageandpageparameters. - Check
licensed_untilbefore assuming a dynamic QR code is active. Expired licenses stop redirecting. - Use
auto_renew: truewith credits to prevent QR codes from going offline unexpectedly. - Set a
fallback_urlon dynamic QR codes so scans still land somewhere if no redirect rules match.