Free plan includes all core tools. Pro unlocks API and bulk workflows. See plans

API Documentation

Integrate EXIF Service into your applications, CMS, or workflows. All endpoints accept multipart file uploads and return processed images.

Getting Started

The EXIF Service API lets you programmatically process images — inject SEO metadata, strip EXIF data, add GPS coordinates, or read metadata. All file-processing endpoints accept multipart/form-data and return the processed file as a download.

Base URL: https://your-domain.com

Content Type: multipart/form-data for uploads

Max File Size: 25 MB per file

Authentication

Most endpoints require authentication. There are two methods:

API Key (Recommended for Integrations)

Generate an API key from your Dashboard → API Keys page (Pro plan required). Include it in the Authorization header:

Authorization: Bearer exs_your_api_key_here

API keys are prefixed with exs_. You can create up to 5 keys. Keys are hashed on our servers — the full key is only shown once at creation.

Session Cookies (Browser-based)

For browser-based usage, sign in via the web form or the auth API. Session cookies are sent automatically.

POST /api/auth/sign-in/email
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "your-password"
}

Rate Limits

Usage is tracked per user (shared across web and API). Limits reset daily at midnight UTC.

Plan Images / Day API Access Bulk Upload
Free 5
Pro ($9/mo) 300

When the limit is exceeded, the API returns 429 Too Many Requests with an upgradeUrl field to direct users to plan upgrade.

Storage and Retention

Processed files are persisted in object storage and linked to your account history. Files are downloadable for 24 hours, then automatically marked deleted (soft delete).

  • Availability window: 24 hours from processing time.
  • After expiry: history rows remain visible, but downloads return 410 Gone.
  • Soft delete: expired files are marked with deleted=true and softDeletedAt.
  • Purge: admins can permanently purge soft-deleted files using the admin files endpoint.
Retention policy summary:
- T+0 to T+24h: user download allowed
- After T+24h: soft deleted, download disabled
- Admin purge: permanent blob + DB delete

View EXIF Data

POST /api/images/view-exif Public

Upload an image and get all its metadata as JSON. No authentication required. If GPS data is present, it's returned in a normalized gps field.

Fields

fileImage file (required)

Example

curl -X POST https://your-domain.com/api/images/view-exif \
  -F "file=@photo.jpg"

Response

{
  "ok": true,
  "metadata": {
    "Make": "Canon",
    "Model": "EOS R5",
    "ExposureTime": "1/250",
    "GPSLatitude": 48.8566,
    ...
  },
  "gps": { "lat": 48.8566, "lng": 2.3522 }
}

SEO EXIF Injection

POST /api/images/seo-exif Auth Required Admin Only

Upload an image and inject SEO metadata (EXIF, IPTC, XMP). This endpoint is reserved for admin workflows only.

Fields

fileImage file (required)
nameAuthor name (required)
titleImage title (required)
descriptionImage description (required)
destinationDestination (required)
cityCity (required)
keywordsComma-separated keywords (required)
categoryCategory (required)
urlURL / license (required)
webFileNameCustom download filename (optional)

Example

curl -X POST https://your-domain.com/api/images/seo-exif \
  -H "Authorization: Bearer exs_your_api_key" \
  -F "file=@photo.jpg" \
  -F "name=John Doe" \
  -F "title=Sunset Beach" \
  -F "description=Beautiful sunset at the beach" \
  -F "destination=Hawaii" \
  -F "city=Honolulu" \
  -F "keywords=sunset,beach,hawaii" \
  -F "category=Travel" \
  -F "url=https://example.com" \
  --output seo-photo.jpg

SEO Metadata Editor (Simple)

POST /api/images/edit-exif Auth Required

Upload an image and set common SEO metadata fields (title, description, author, keywords, copyright), plus rights/licensing fields used in Google and IPTC metadata workflows. Returns the processed image as a file download.

Fields

fileImage file (required)
titleImage title (optional)
descriptionImage description (optional)
authorAuthor / artist name (optional)
keywordsComma-separated keywords (optional)
copyrightCopyright notice (optional)
creditLineCredit line / attribution text (optional)
sourceIPTC source/origin text (optional)
webStatementUrlRights or license page URL (optional)
licensorNameLicensor display name (optional)
licensorUrlLicensor URL/contact page (optional)
usageTermsUsage terms / legal instructions (optional)
creatorUrlCreator website URL (optional)
creatorEmailCreator contact email (optional)
digitalSourceTypeIPTC DigitalSourceType URI (optional)
modeappend (default) or overwrite

Example

curl -X POST https://your-domain.com/api/images/edit-exif \
  -H "Authorization: Bearer exs_your_api_key" \
  -F "file=@photo.jpg" \
  -F "title=Mountain Sunset" \
  -F "description=A beautiful sunset over the mountains" \
  -F "author=Jane Doe" \
  -F "keywords=sunset,mountains,landscape" \
  -F "copyright=2026 Jane Doe" \
  -F "creditLine=Jane Doe Photography" \
  -F "source=EXIFCut" \
  -F "webStatementUrl=https://example.com/license/mountain-sunset" \
  -F "licensorName=Jane Doe Licensing" \
  -F "licensorUrl=https://example.com/contact-license" \
  -F "usageTerms=Editorial use only unless licensed" \
  -F "creatorUrl=https://janedoe.com" \
  -F "creatorEmail=rights@janedoe.com" \
  -F "digitalSourceType=http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia" \
  --output edited-photo.jpg

Advanced EXIF Editor

POST /api/images/advanced-edit Auth Required

Upload an image and set arbitrary EXIF/IPTC/XMP fields using a JSON object. Supports any writable ExifTool tag including nested fields with dot notation (e.g. IPTC.Keywords). Returns the processed image as a file download.

Fields

fileImage file (required)
fieldsJSON string of key-value pairs to write (required)
modeappend (default) or overwrite — overwrite strips existing metadata first

Example

curl -X POST https://your-domain.com/api/images/advanced-edit \
  -H "Authorization: Bearer exs_your_api_key" \
  -F "file=@photo.jpg" \
  -F 'fields={"Title":"Sunset","Artist":"Jane","Orientation":1,"GPSLatitude":48.8566,"GPSLongitude":2.3522}' \
  -F "mode=append" \
  --output edited-photo.jpg

Bulk Advanced Edit

POST /api/images/advanced-edit-bulk Auth Required Pro

Upload up to 20 images and apply the same metadata fields to all of them. Returns a ZIP archive containing all edited images.

Fields

filesImage files, up to 20 (required). Use multiple -F "files=@..." flags.
fieldsJSON string of key-value pairs to write (required)
modeappend (default) or overwrite

Example

curl -X POST https://your-domain.com/api/images/advanced-edit-bulk \
  -H "Authorization: Bearer exs_your_api_key" \
  -F "files=@photo1.jpg" \
  -F "files=@photo2.jpg" \
  -F "files=@photo3.jpg" \
  -F 'fields={"Copyright":"2026 Jane Doe","Artist":"Jane Doe"}' \
  --output edited-images.zip

Strip EXIF Data

POST /api/images/strip-exif Auth Required

Upload an image and remove all EXIF metadata. Returns the clean image as a file download.

Fields

fileImage file (required)

Example

curl -X POST https://your-domain.com/api/images/strip-exif \
  -H "Authorization: Bearer exs_your_api_key" \
  -F "file=@photo.jpg" \
  --output clean-photo.jpg

Bulk Strip EXIF

POST /api/images/strip-exif-bulk Auth Required Pro

Upload up to 20 images and strip all metadata. Returns a ZIP archive containing all cleaned images.

Fields

filesImage files, up to 20 (required). Use multiple -F "files=@..." flags.

Example

curl -X POST https://your-domain.com/api/images/strip-exif-bulk \
  -H "Authorization: Bearer exs_your_api_key" \
  -F "files=@photo1.jpg" \
  -F "files=@photo2.jpg" \
  -F "files=@photo3.jpg" \
  --output cleaned-images.zip

Geo Data Injection

POST /api/images/geo-exif Auth Required

Upload an image and inject GPS coordinates. Returns the geotagged image as a file download.

Fields

fileImage file (required)
latitudeGPS latitude, -90 to 90 (required)
longitudeGPS longitude, -180 to 180 (required)
altitudeAltitude in meters (optional)

Example

curl -X POST https://your-domain.com/api/images/geo-exif \
  -H "Authorization: Bearer exs_your_api_key" \
  -F "file=@photo.jpg" \
  -F "latitude=48.8566" \
  -F "longitude=2.3522" \
  -F "altitude=35" \
  --output geotagged-photo.jpg

Processing History

GET /api/images/history Auth Required

Returns the authenticated user's last 50 processed images with lifecycle status. Set Accept: application/json for JSON output, otherwise returns an HTML fragment for dashboard rendering.

Example

curl https://your-domain.com/api/images/history \
  -H "Authorization: Bearer exs_your_api_key" \
  -H "Accept: application/json"

JSON Response

{
  "ok": true,
  "images": [
    {
      "id": "...",
      "fileName": "photo.jpg",
      "tool": "strip-exif",
      "createdAt": "2026-03-01T12:00:00.000Z",
      "downloadExpiresAt": "2026-03-02T12:00:00.000Z",
      "status": "available",
      "canDownload": true,
      "downloadUrl": "/api/images/history/.../download"
    }
  ]
}

History Download

GET /api/images/history/:id/download Auth Required

Downloads a previously processed file owned by the authenticated user. The endpoint enforces the 24-hour retention window.

Path Params

idHistory item id from /api/images/history

Example

curl -L https://your-domain.com/api/images/history/65f.../download \
  -H "Authorization: Bearer exs_your_api_key" \
  --output my-image.jpg

Status Codes

200File stream download started
404Record not found
410Download window expired

API Key Management

API keys are available to Pro users and are used for server-to-server access. Use session auth in the dashboard to create and revoke keys.

GET /api/keys

Lists masked keys for the authenticated user with creation and last-used timestamps.

POST /api/keys

Creates a new API key. Request body: name (optional). Returns the raw key once.

curl -X POST https://your-domain.com/api/keys \
  -H "Content-Type: application/json" \
  -H "Cookie: your_session_cookie" \
  -d '{"name":"CI Pipeline"}'

DELETE /api/keys/:id

Revokes a key by id for the authenticated owner.

Billing API

Billing endpoints require an authenticated user session and are used by the dashboard to manage upgrades and subscriptions.

POST /api/billing/checkout

Creates a Stripe Checkout session for the Pro plan and returns url for redirect.

POST /api/billing/portal

Creates a Stripe Billing Portal session so users can manage their active subscription.

GET /api/billing/status

Returns current plan, daily usage, plan limit, and global limits for free/pro plans.

Feedback API

Feedback and feature requests can be submitted by authenticated users or public visitors.

POST /api/feedback Public

Fields

typefeedback or feature
subjectShort summary (optional)
messageRequired, minimum 10 characters
nameOptional display name
emailRequired for guests, optional for authenticated users
sourcePathOptional source page/path hint
curl -X POST https://your-domain.com/api/feedback \
  -H "Content-Type: application/json" \
  -d '{
    "type": "feature",
    "subject": "Bulk presets",
    "message": "Please add reusable metadata presets for bulk edits.",
    "name": "Jane",
    "email": "jane@example.com",
    "sourcePath": "/dashboard/feedback"
  }'

Admin File Management

These endpoints require an authenticated admin user session.

GET /api/admin/files

Returns an HTML table of uploaded files with user, status, and download action. Supports query params: status=all|available|deleted, userId, limit.

GET /api/admin/files/:id/download

Downloads a stored file by id for support or compliance workflows.

POST /api/admin/files/purge

Permanently deletes soft-deleted files older than 24 hours from storage and database.

curl -X POST https://your-domain.com/api/admin/files/purge \
  -H "Cookie: your_admin_session_cookie"

Error Codes

All errors return JSON with ok: false and a message field. Plan-related errors also include error and upgradeUrl.

Status Meaning
400 Bad Request — missing or invalid fields
401 Unauthorized — missing or invalid API key / session
403 Forbidden — feature requires a higher plan (e.g., API access needs Pro)
429 Too Many Requests — daily usage limit exceeded
500 Server Error — unexpected error during processing

Plan Limit Error Example

{
  "ok": false,
  "error": "limit_reached",
  "message": "Daily limit of 5 images reached. Upgrade your plan for more.",
  "upgradeUrl": "/pricing"
}