Integration · Object storage

A container of exports, read on a cadence.

SharedKey auth against a storage account and container. Read the newest blob since the last run and map it; or write the mapped result back as one timestamped blob.

POST /v1/connectors/{id}/synckind: azure_blob

How it works

What actually happens on a sync run

Azure signs differently from the other two — SharedKey over a canonicalized request rather than SigV4 or an OAuth token — and answers its listing in its own XML dialect. Everything above that is identical: list the prefix, take the newest blob modified since the last successful run, parse it by its own name, map it. The account key lives in the connector record, encrypted, and is never accepted in a request body.

  1. Step 1

    Sign with SharedKey

    The canonicalized request is signed with the account key on every call.
  2. Step 2

    List and filter

    The container listing is normalized to the same object shape S3 and GCS produce, then filtered against the watermark.
  3. Step 3

    Parse by name

    The blob name’s extension chooses the parser — text or binary.
  4. Step 4

    Map and land

    An upload under your retention setting, then the cascade.

What you get

Built for files that keep arriving

Auth

SharedKey, encrypted at rest

The account key is stored envelope-encrypted and read only by the signer. A GET of the connector returns a four-character hint, never the key.

How · signAzureRequest() builds the canonicalized string per call. Rotation happens in place via /rotate-secret, which overwrites the old key with no recovery window by design.

Incremental

Newest blob since the last successful run

A quiet container costs nothing but a listing, and reports success with zero rows rather than an error.

How · The watermark is last_synced_at, overridable with ?since=. It advances only when the run succeeded.

Sovereign clouds

A non-public Azure environment is one field

Set the endpoint suffix and the same connector signs against a sovereign or government cloud host.

How · config.endpoint_suffix changes the host the signer targets; the SSRF guard still resolves and checks it like any other outbound request.

Secrets

The credential never travels in a request body

You reference a connector by id. Keys, tokens and service-account JSON are encrypted at rest and read only by the code that makes the call.

How · normalizeSecretField() folds every provider spelling — private_key, token, secret_access_key, account_key, service_account_json — into one auth_value field, which is KEK-envelope-encrypted before the row is written. A GET masks it to a 4-character hint. If encryption fails the field is dropped rather than stored in plaintext.

Configuration

The connector record, field by field

KeyRequiredWhat it is
containerRequiredContainer name. bucket is accepted as an alias.
accountRequiredStorage account name. Required, and checked at save time.
auth_valuesecretRequiredThe account key. account_key is accepted as an alias and folded into this field before storage.
endpoint_suffixOptionalNon-public cloud suffix, for a sovereign or government Azure environment.
prefixOptionalBlob prefix scoping the read and the write.
formatOptionalOverride extension sniffing.
urlOptionalLegacy presigned/SAS URL form. Read-only.

In code

A container drop, mapped on the next tick.

Save the account and container once; pull it on demand with a bearer key, or let the scheduled cadence on the record do it.

  • POST/v1/connectorsSave the connector. The secret is encrypted before it reaches Postgres.session
  • POST/v1/connectors/{id}/testMake a real call and report what was actually proven.session
  • POST/v1/connectors/{id}/syncPull now. Accepts ?since=<iso> to override the watermark.bearer
  • POST/v1/gatewayAny input in, this destination populated, a delivery report out.bearer
  • POST/v1/connectors/{id}/rotate-secretReplace the credential in place; the old one becomes unrecoverable.session
  • The blob’s own name decides the parser, so an .xlsx export needs no configuration at all.
  • Azure’s error bodies are XML; the provider’s message is surfaced verbatim because an AuthenticationFailed is the actionable part.
  • Blobs are capped at 25 MiB and calls time out at 60 seconds.
POST /v1/connectors
{
  "kind": "azure_blob",
  "name": "Payroll drop",
  "template_id": "payroll",
  "config": {
    "account": "acmepayroll",
    "container": "exports",
    "prefix": "monthly/",
    "account_key": "…"
  }
}
curl
curl -X POST https://api.adaptivmapr.com/v1/connectors/con_ab77…/sync \
  -H "Authorization: Bearer $MAPR_API_KEY"
response
{
  "ok": true,
  "status": "parsed",
  "upload_id": "upl_5c02…",
  "row_count": 412,
  "accepted": 412,
  "format": "xlsx",
  "incremental": "incremental"
}
→ one blob read · parsed as xlsx from the blob name · 412 of 412 rows accepted

Limits & failure modes

What it refuses, and what it tells you

CodeWhenWhat to do
400 ssrf_blockedThe configured host resolves to a private, link-local or loopback address.Every outbound request is DNS-resolved and checked before it is made, on the scheduled path and the on-demand path alike. The reason is returned with the code.
400 config_invalidA credential or identifier the provider needs is missing or malformed.Refused at save time rather than at 3am during a scheduled run. The message names the exact key.
400 config_invalidNo account, or no account key.Both are checked before the record is created; a container with no way to sign for it is never saved.
413 fetch_too_largeThe chosen blob exceeds 25 MiB.Split it upstream. The ceiling is the parser’s memory envelope, not an Azure limit.
502 fetch_failedAzure refused the list or the get.Its own message is passed through and the watermark is left where it was.

Incremental sync

Real, by blob modified time — the listing is filtered against the watermark and only the newest survivor is read. An empty result is status: "not_modified", a success.

PHI & residency

A blob sync runs under the workspace’s routing policy, not around it. PHI routing is a separate axis from the data mode: it sends X-PHI and X-Region to phi-cloud so a regulated run lands on an in-region, BAA-eligible model, it costs +20% on the whole charge, and it is locked until the workspace accepts the BAA in Settings → Security & Data. An explicit PHI ask without an acceptance is 403 agreement_required, never a silent downgrade. A standard run keeps the workspace’s region pin — the region decides where compute may run, and the sandbox refuses a region-less run.

What it costs

Billed on the same prepaid wallet

Moving bytes is not a line item. A sync that pulls a file and a destination write that lands the rows are both part of one map, and the map is what the wallet sees. There is no free tier and no subscription — top up from $10, a balance shared across the phi-cloud suite.

ChargeRateNotes
Every map$0.001A flat per-map fee — a few tokens — charged even when the run was fully deterministic or hit the layout cache and used no AI at all.
AI, only when it ranat cost × 2Layer-5 cleanup, any-to-any convert and structural reshape bill the phi-cloud tokens actually consumed. Bring your own model key and it is × 0.5.
PHI / enterprise routing+20%Multiplies the whole charge, flat fee included — and only when the run genuinely got that routing. Locked until the workspace accepts the BAA in-app.

Questions

Before you wire it up

A SAS URL works through the legacy presigned-URL form, which is read-only. The credentialled path — the one that can also write — signs with SharedKey and needs the account name and account key. The key is envelope-encrypted before it reaches storage and is never returned in an API response.
Yes. Set config.endpoint_suffix and the signer targets that host. The SSRF guard resolves and checks the host like every other outbound request, so a suffix that resolves to a private range is refused rather than dialled.
A connector record carries a cadence of hourly, daily or weekly, and an hourly Worker cron fires the ones whose last successful sync is older than that window — 60 minutes, 24 hours or 7 days respectively — up to 1000 connectors per tick. On-demand pulls go through POST /v1/connectors/{id}/sync at any time.
The parsed grid becomes an upload under your workspace retention setting — 24 hours by default in Cloudflare KV — and the blob itself is left exactly where it was. AdaptivMapr never deletes or moves your source data.

Verified against lib/objectStore.ts · lib/cloudAuth.ts · lib/connectorSyncRunner.ts · app/api/v1/connectors/route.ts

Azure and Azure Blob Storage are trademarks of Microsoft Corporation. Named here to describe interoperability only — no affiliation, endorsement or partnership is claimed.

Ready when you are

Point it at Azure Blob Storage. Get your schema back.

Start with a $10 prepaid wallet. Every map draws a few tokens; in schema-only mode only headers and a few sample rows ever leave you.

$10 minimum to start · pay only for what you map · PHI under BAA coverage
Azure Blob Storage integration — scheduled container ingest & write-back — AdaptivMapr — AdaptivMapr