Skip to main content

Records

A Record is the creator-declared data attached to a signature the partner registered. It says where and when the media is allowed to appear, carries display metadata such as a byline and a purchase URL, and is what SASHA evaluates to return guidance when someone later looks the media up.

Here is a Record that restricts a photo to one publisher, from an embargo date, with a credit line:

{
"share_state": "restricted",
"allowed_publish_urls": ["https://news.example.com/articles/"],
"allowed_source_urls": ["https://cdn.example.com"],
"allowed_from": "2026-07-01T06:00:00Z",
"byline": "Photo by Jane Doe",
"purchase_url": "https://license.example.com/photos/123"
}

A signature works with no Record at all — it is then treated as private. Attaching a Record is how a creator declares intent and exposes metadata to the parties who find the media.

To create, read, update, or delete Records, see Manage Records.

Share state

Every Record opens with a share_state — the top-level statement of distribution intent. It is required, and it drives how the rest of the Record is interpreted.

Share stateMeaning
privateThe media is not intended to be distributed publicly anywhere.
unrestrictedThe creator declared no distribution restrictions.
restrictedThe media is allowed only where the Record's distribution fields permit.

private and unrestricted must not carry any distribution fields — the share state says everything. Only restricted reads the URL patterns and time window below.

A share state describes only the intent a creator declared to SASHA. It is not a statement about the legal status of the media; rights such as copyright apply independently.

Distribution intent

Under restricted, four optional fields describe where and when the media may appear:

  • allowed_publish_urls — patterns the browser-facing display URL may match (e.g. an article page).
  • allowed_source_urls — patterns the storage/CDN address of the bytes may match.
  • allowed_from / allowed_to — the time window the media may be available (supports embargo and expiry).

These fields form a permit list: every condition present must hold for the media to be allowed at a location, and a restricted Record that carries none of them yet permits nothing. That is deliberate: the restriction can be declared first and the conditions added as they become known, without opening the media up in the meantime.

Each field holds up to 100 patterns, each up to 2048 characters.

URL pattern syntax

A pattern is a host, optionally with a path. The scheme may be omitted; https is implied and is the only scheme accepted.

PatternMatches
news.example.comany path on that host
news.example.com/articles/the /articles/ prefix, at segment boundaries: /articles, /articles/123, /articles/123/amp — but not /articles-archive
news.example.com/articles/123that path exactly, and nothing under it
*.example.comany subdomain, at any depth — but not the apex example.com itself
  • A trailing / is what makes a path a prefix. Without it the path matches exactly, so news.example.com/articles/123 does not permit /articles/123/amp.
  • * is a host-label wildcard only, and only the leftmost label. There is no path wildcard: news.example.com/articles/* is not a valid pattern. news.example.com/articles/ expresses the same intent, and news.example.com allows any path on the host.
  • The scheme and port must match exactly. Patterns are https on port 443 unless a port is written in, so an http:// location never matches and evaluates to not_allowed. A non-default port belongs in the pattern: news.example.com:8443/articles/.
  • Host matching is case-insensitive, path matching is case-sensitive. news.example.com/Articles/ does not match /articles/123.

A pattern is rejected if it uses a scheme other than https, carries userinfo, a query string or a fragment, addresses an IP literal or localhost, is a bare * (declare unrestricted instead), places a wildcard anywhere but the leftmost label, or wildcards a public suffix such as *.com or *.github.io. A path of / is rejected too — it matches every path, which is what a bare host already means.

A rejected pattern fails the write with a field violation naming the entry, for example allowed_publish_urls[1]. The reason reports which rule was broken — UNSUPPORTED_SCHEME, FORBIDDEN_USERINFO, FORBIDDEN_HOST, TOO_LONG, EMPTY, or INVALID_PATTERN for a shape the grammar cannot parse. See Error Handling.

Query strings and fragments are ignored when a candidate URL is matched, so a pattern cannot restrict by them. Media addressed only by a query parameter — example.com/view?id=123 — cannot be expressed at per-item granularity in this version. A location that does not parse as a URL at all is unevaluable rather than disallowed, and contributes inconclusive.

Display metadata

Independent of distribution intent, a Record can carry metadata for the parties who find the media. These fields are display/metadata only and never affect guidance, so they are valid under any share state:

  • byline — credit text a publisher is expected to show (e.g. "Photo by Jane Doe").
  • purchase_url — an https URL where the media can be licensed or bought.
  • licensee — the legal business name of the entity that licensed the asset.
  • asset_source_id — the creator's own upstream identifier for the media in their system (a UUID is recommended, not required).
  • custom_fields — up to 32 custom typed fields, keyed by a name of the creator's choosing, for anything the fixed fields don't cover.
{
"share_state": "unrestricted",
"byline": "Photo by Jane Doe",
"licensee": "Example Media Group Ltd.",
"asset_source_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"custom_fields": {
"internal_asset_id": { "string_value": "asset-9f3c" },
"is_exclusive": { "boolean_value": true }
}
}

Guidance on lookup

When a lookup finds a signature, SASHA evaluates its Record against the context the looker supplied — the publish_url and source_url where the media was found — and returns coarse guidance on the completed job. The looker never sees the Record's raw fields this way.

{
"share_state": "restricted",
"advice": "not_allowed"
}

advice is one of three closed values:

AdviceWhen
allowedThe location and time are consistent with the declared intent.
not_allowedThe location or time conflicts with it, the media is private, or the Record is restricted and carries no distribution fields at all — an empty permit list permits nothing.
inconclusiveNo verdict could be produced: a restricted Record that carries URL patterns, looked up without the matching publish_url or source_url.

A conflict outweighs a missing answer. An embargo that has not opened yet returns not_allowed even when no URL context was supplied, because the time condition can be evaluated on its own.

Guidance carries an optional message field, reserved for a future human-readable explanation. It is not returned today. Branch on advice and share_state.

A revoked signature is still detected in the media, but its completed job carries no guidance and discloses no Record — to anyone, including the owner.

For the request shape and how to read guidance off a job, see Manage Records: guidance on lookup.

Who can read a Record

A Record's fields are private by default. Disclosure has four tiers:

  1. The owner — always reads the full Record, durably, via GetSignatureRecord. This never depends on a lookup.
  2. A granted creator — receives the specific fields the owner granted, on a lookup they performed.
  3. Any looker — receives fields the owner marked public, on a lookup they performed.
  4. Everyone else — receives no Record, only guidance.

Grants and public-field markers are part of the creator's record-access policy, managed by SASHA on the creator's behalf. Marking a field public is a deliberate, per-field, effectively irreversible opt-in: once a value has been returned to an arbitrary looker it is out, though disclosure can be stopped going forward.

Disclosure to a looker is possession-bound and time-bounded: a granted or public field arrives on the completed lookup job that looker submitted, is held only transiently, and ages out even though guidance remains. The owner's durable read is always GetSignatureRecord.

Limits

A Record that exceeds any of these is rejected on write, naming the field.

FieldLimit
allowed_publish_urls, allowed_source_urls100 patterns each, 2048 characters per pattern
byline, licensee, asset_source_id256 characters each, no control characters
purchase_url2048 characters
custom_fields32 entries; keys 64 characters; a string_value up to 1024 characters
the Record as a whole64 KiB once stored

The text limits — byline, licensee, asset_source_id, and custom_fields keys and string values — count Unicode code points, so an emoji counts as one character. The URL and pattern limits count UTF-16 code units, which only differs outside the Basic Multilingual Plane and so rarely matters for a URL.

Each custom_fields entry sets exactly one typed value — string_value, boolean_value, int32_value, double_value or uuid_value. Setting none, or more than one, is rejected with EXACTLY_ONE_REQUIRED. A uuid_value is exactly 16 raw bytes, base64-encoded on REST.

See also