Skip to main content

Squillify development is paused indefinitely. Read why, and discover what this experiment achieved. Read the story

MicroSkills Reference

Geocode Batch Plan and Normalize

data.geocode_batch_stub

ProductionBounded custom (Class B)Deterministicstrictinstantv1.0.0
No network

Overview

Two services over the provider profile you declare, and neither one sends anything. Under PLAN you get the requests you would send: batched addresses, substituted and percent-encoded URLs, query parameters or a form body, and pacing arithmetic derived from your own rate-limit hints. Under NORMALIZE you hand back the responses your client received and get one canonical shape: an address index, a coordinate, and a precision from a closed eight-member scale. There is no apiKey, token or headers field in this schema at all and the profile key set is closed, so a credential cannot arrive under an unfamiliar name and end up in a plan that gets logged, diffed and pasted into a ticket.

The two halves of a geocoding integration that do not need the network are the two halves that are easy to get wrong.

Reliability

The same request always gives the same plan or the same normalised answers, on any machine and under any locale, time zone or default charset: percent-encoding is written out over UTF-8 bytes and credential name matching folds at the root locale, so neither moves with the host. projectedWallClockMs is (requestCount - 1) x minIntervalMs, arithmetic over the hints you supplied rather than a measurement, because this skill reads no clock. Under NORMALIZE a malformed entry is per-entry and a miscounted one is fatal: an entry that does not parse, that lacks the array at resultPath, or that carries a latitude outside -90 to 90 or a longitude outside -180 to 180 lands in rejected[] and the call still succeeds with partial true, because one bad provider row must not discard 999 good ones and a coordinate is never clamped; but a response whose result count disagrees with the addresses of the request it answers is refused outright, since positional realignment is the one error that attaches the right coordinates to the wrong address. A provider precision absent from precisionMapping normalises to UNKNOWN rather than into a neighbouring band. Fifteen refusals, none retryable unchanged: GEOCODE_MODE_UNSUPPORTED when mode is not PLAN or NORMALIZE, so choose one of those two values; GEOCODE_ADDRESSES_INVALID, GEOCODE_ADDRESS_LIMIT_EXCEEDED above 1000 and GEOCODE_ADDRESS_TOO_LONG above 1024 code points, so shorten or split the address list before retrying; GEOCODE_PROFILE_INVALID and GEOCODE_PROFILE_KEY_UNSUPPORTED for the profile, whose key set is closed; GEOCODE_CREDENTIAL_FORBIDDEN when a parameter name matches the credential vocabulary in staticParameters, in parameterMapping or already inside the endpoint query; GEOCODE_ENDPOINT_INVALID for a non-https endpoint, a missing host or userinfo; GEOCODE_PLACEHOLDER_UNSUPPORTED outside the four placeholders; GEOCODE_PARAMETER_UNSUPPORTED outside the request vocabulary or for a role nothing supplies; GEOCODE_BATCH_SIZE_INVALID outside 1 to 100, so set a supported provider batch size; GEOCODE_RESPONSES_REQUIRED and GEOCODE_RESPONSES_FORBIDDEN when the mode and the payload disagree; GEOCODE_RESPONSE_CARDINALITY_MISMATCH when response counts cannot align positionally, so supply exactly one response per planned request with one result per address; and GEOCODE_OUTPUT_TOO_LARGE when the plan or the answers would not fit the inline response ceiling.

Context footprint

A plan is roughly one URL per batch; normalised answers are one small object per address, with any formatted address cut at 256 code points. A successful call costs 1 execution credit.

When to use it

When you want the request plan, the pacing arithmetic or one canonical answer shape, and you will do the sending yourself.

When you expected a coordinate for an address — nothing here looks one up.

Scope

Note
Plans geocoding requests and normalises provider responses, offline.

Non-goals

  • Does not perform any network call, in either mode
  • Does not accept, store or forward a credential of any kind
  • Does not geocode an address itself or hold any gazetteer
  • Does not clamp a coordinate that falls outside its valid range
  • Does not guess a precision a provider did not declare

Properties

IdempotentRetry safeStreaming supportedFile input supportedRequires external service

Capabilities

data-transformation

Cost & billing

Flat rate per invocation

MetercallsBillable onsuccessCost per call1 credit

File handling

Accepts file_refProduces file_refMax input1 MB

How we handle your data

Sensitive output possible
What this means

This skill may receive sensitive content and may return submitted, transformed, extracted, or reformatted content.

Squillify guarantees
  • Runs inside Squillify
  • This skill runs inside Squillify.
  • Payloads are not sent to an external service by this skill.
  • Squillify does not permanently store submitted payloads.
  • Telemetry records metadata only, not submitted content.
  • Submitted payloads are not used for training.
  • Submitted payloads are not reviewed by humans.
  • This skill does not target sensitive data.
  • The response may contain submitted or transformed content.
Your responsibility

Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.

Read the Microskill Data Handling Policy

Input schema

FieldTypeRequiredDescription
modestringNoPLAN builds requests; NORMALIZE maps responses; omit it for PLAN.
addressesarrayYesBounded array of 1 through 1000 address strings whose indexes are reused on every planned request.
providerProfileobjectYesClosed nine-key provider profile; extra keys are refused so a credential cannot hide under an unfamiliar name.
providerResponsesarrayNoBounded array of provider JSON strings, one per planned request. Required unless mode is PLAN.

Output schema

FieldTypeRequiredDescription
requestsarrayNoBounded array of 0 through 1000 closed planned requests; PLAN only.
pacingobjectNoClosed pacing projection derived from your rate-limit hints, not a measurement.
normalizedarrayNoBounded array of 0 through 1000 closed canonical answers; NORMALIZE only.
rejectedarrayNoBounded array of 0 through 1000 closed rejections; NORMALIZE only.
summaryobjectYesClosed PLAN or NORMALIZE summary; PLAN uses addressCount and requestCount, NORMALIZE uses requested and match counts.

API contract

POST /v1/execute
curl
curl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"data.geocode_batch_stub","input":{"addresses":["Dam 1, Amsterdam"],"providerProfile":{"endpointTemplate":"https://api.example.invalid/v1/search?q={query}"}}}'
Integrations
TypeScript SDK
import { Squillify } from "@squillify/sdk";

const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });

const { output } = await sq.execute("data.geocode_batch_stub", {"addresses":["Dam 1, Amsterdam"],"providerProfile":{"endpointTemplate":"https://api.example.invalid/v1/search?q={query}"}});

Errors

CodeHTTPRetryableDescription
VALIDATION_ERROR400NoThe request payload failed schema validation.
UNAUTHORIZED401NoMissing or invalid API key.
SKILL_NOT_ACCESSIBLE403NoThe API key is not granted access to this skill.
SKILL_NOT_AVAILABLE_FOR_PLAN403NoThis skill is not included in your current plan.
PLAN_ELIGIBILITY_UNAVAILABLE503YesPlan eligibility could not be decided. Retry after backoff.
SKILL_NOT_FOUND404NoThe requested skill or version does not exist.
TENANT_RATE_LIMITED429YesRequest rate limit exceeded. Retry after backoff.
QUOTA_EXCEEDED429YesPlan quota exhausted. Retryable once the quota period resets.
EXECUTION_TIMEOUT504YesExecution exceeded the allowed time budget.
GEOCODE_MODE_UNSUPPORTED400NoThe skill does not support the requested variant.
GEOCODE_ADDRESSES_INVALID400NoThe request payload failed this skill's input validation.
GEOCODE_ADDRESS_LIMIT_EXCEEDED429NoA size, quota, rate, or time limit was exceeded.
GEOCODE_ADDRESS_TOO_LONG429NoA size, quota, rate, or time limit was exceeded.
GEOCODE_PROFILE_INVALID400NoThe request payload failed this skill's input validation.
GEOCODE_PROFILE_KEY_UNSUPPORTED400NoThe skill does not support the requested variant.
GEOCODE_CREDENTIAL_FORBIDDEN403NoThe operation is forbidden by policy or permissions.
GEOCODE_ENDPOINT_INVALID400NoThe request payload failed this skill's input validation.
GEOCODE_PLACEHOLDER_UNSUPPORTED400NoThe skill does not support the requested variant.
GEOCODE_PARAMETER_UNSUPPORTED400NoThe skill does not support the requested variant.
GEOCODE_BATCH_SIZE_INVALID400NoThe request payload failed this skill's input validation.
GEOCODE_RESPONSES_REQUIRED400NoThe request payload failed this skill's input validation.
GEOCODE_RESPONSES_FORBIDDEN400NoThe request payload failed this skill's input validation.
GEOCODE_RESPONSE_CARDINALITY_MISMATCH400NoThe request payload failed this skill's input validation.
GEOCODE_OUTPUT_TOO_LARGE429NoA size, quota, rate, or time limit was exceeded.

Other limits

LimitValue
Recommended inline bytes32 KiB

Limitations

  • Does not perform any network call, in either mode
  • Does not accept, store or forward a credential of any kind
  • Does not geocode an address itself or hold any gazetteer
  • Does not clamp a coordinate that falls outside its valid range
  • Does not guess a precision a provider did not declare
  • Actually calling a geocoding provider
  • Anything requiring an API key to be supplied here

How to call

POST /v1/execute (requires authentication)

Request bodyjson
{
  "skillKey": "data.geocode_batch_stub",
  "input": {
    "addresses": [
      "Dam 1, Amsterdam"
    ],
    "providerProfile": {
      "endpointTemplate": "https://api.example.invalid/v1/search?q={query}"
    }
  }
}

Examples

A single-address plan

Inputjson
{
  "addresses": [
    "Dam 1, Amsterdam"
  ],
  "providerProfile": {
    "endpointTemplate": "https://api.example.invalid/v1/search?q={query}"
  }
}
Expected outputjson
{
  "pacing": {
    "projectedWallClockMs": 0,
    "requestCount": 1,
    "burst": 1,
    "requestsPerSecond": 1,
    "batchSize": 1,
    "minIntervalMs": 0
  },
  "summary": {
    "truncated": false,
    "addressCount": 1,
    "requestCount": 1
  },
  "requests": [
    {
      "method": "GET",
      "index": 0,
      "url": "https://api.example.invalid/v1/search?q=Dam%201%2C%20Amsterdam",
      "queryParameters": [],
      "addressIndexes": [
        0
      ]
    }
  ]
}

Normalize one GeoJSON provider response

Inputjson
{
  "providerProfile": {
    "endpointTemplate": "https://api.example.invalid/v1/search?q={query}",
    "precisionMapping": {
      "house": "ROOFTOP"
    }
  },
  "providerResponses": [
    "{\"features\":[{\"geometry\":{\"coordinates\":[4.8952,52.3702]},\"properties\":{\"precision\":\"house\",\"formatted\":\"Dam 1, Amsterdam\",\"components\":{\"road\":\"Dam\",\"city\":\"Amsterdam\"}}}]}"
  ],
  "addresses": [
    "Dam 1, Amsterdam"
  ],
  "mode": "NORMALIZE"
}
Expected outputjson
{
  "normalized": [
    {
      "longitude": 4.8952,
      "matched": true,
      "formatted": "Dam 1, Amsterdam",
      "addressIndex": 0,
      "latitude": 52.3702,
      "componentCount": 2,
      "precision": "ROOFTOP"
    }
  ],
  "summary": {
    "partial": false,
    "matchedCount": 1,
    "rejectedCount": 0,
    "truncated": false,
    "requested": 1
  },
  "rejected": []
}
  • Preparing a batch of provider requests with correct pacing
  • Turning two providers' answers into one comparable shape
  • Reviewing exactly what would be sent before anyone sends it

Avoid for

  • Actually calling a geocoding provider
  • Anything requiring an API key to be supplied here

Composable with

Safety & privacy

  • Runs without calling any external service.
  • Your payloads are never stored permanently.
  • Telemetry captures metadata only — never your payload contents.
  • We never train models on your payloads.
  • No human reviews your payloads.

Tags

geocodingvalidationdata