Skip to main content
All calls go to https://actions.pool.day over TLS with the app key as a bearer token. None carries an image, a file name or a photo identifier. By default PoolKit makes only the first one.

Register an install

key.expiresAt is set while a rotated key is in its 30-day grace. When cloud assist is off for the install, cloudAssist says why. { "enabled": false, "reason": "disabled" } means the app turned it off in the dashboard. { "enabled": false, "reason": "quota_exceeded", "retryAfter": 86400 } means the month’s installs or cloud assist units are spent; the SDK registers again after retryAfter seconds and picks up a raised allowance or a new month. Everything on the device keeps working either way. Sent when the client opens. The install ID is random, made by the SDK, stored in your app’s container, and reset when the app is reinstalled. It is how connected users are counted: once per install per calendar month.

List the engine’s models

PoolKit downloads each file once, checks it against the SHA-256 given here before loading it, and keeps it in your app’s container. The models run on the device. Nothing about a photo is part of this call.

Cloud assist: name things

Cloud assist: answer a question

  • The context is what PoolKit found on the device under the grant: up to 40 things and excerpts of up to 400 characters. A ref is a random reference that means nothing outside the request.
  • Every citation is a ref from the request. Pool drops any other, so an answer cannot point at something the device did not send.
  • declined is true, with no text, when answering would mean inferring something sensitive or identifying a person.
  • Pool does not store or log the question, the context or the answer.
  • A question is 1 to 1,000 characters.
With Accept: text/event-stream, the same call answers as the model writes, for askUpdates. A refusal before the first word is the usual JSON error. Otherwise the body is Server-Sent Events:
  • delta events carry the next words. The final answer is checked like the JSON answer and can be declined after deltas, so drop the text you showed.
  • When the model fails partway, the last event is error with {"error":{"code","message"},"retryAfter":30} and the units are given back.
  • The 10 units are charged once the answer event is sent. If the app closes the stream before the first delta, they are given back; once words have arrived, closing it keeps the charge.

Cloud assist: fill a profile

  • Up to 80 context entries. The schema is a small part of JSON Schema: objects, arrays, strings, numbers, integers, booleans and enums, up to 5 levels, 100 fields and 32 KB. A schema outside that gets a 400 with code invalid_schema and a sentence that says why.
  • A field is filled only when its value fits the schema and rests on at least one ref from the request. Every other field is null and listed in refused with no_evidence, sensitive or invalid.
  • Fields about health, religion, sexuality, ethnicity, politics, children, finances or credentials are never filled, whatever the evidence.
  • Pool does not store or log the schema, the context or the profile.

Cloud assist: judge captures against a rule

  • rule is up to 500 characters of plain words. items holds up to 24 captures; each needs text, a label or a thing name.
  • belongs is the probability that the capture is what the rule describes. incidental is the probability that it is system or app chrome instead of something the person saved. insufficient is the probability that the text is too thin to judge. member is true when belongs is at least 0.7 and incidental is under 0.45.
  • A capture missing from results was not reached this time. retryAfterSeconds is present only then and says when to send it again.
  • Four captures count as one unit, rounded up per request. Captures that were not reached are not charged.
  • A rule about health, religion, sexuality, ethnicity, politics, children, finances or credentials is refused with 400 and the code rule_not_allowed, before anything is read.
  • Pool does not store or log the rule or the text. It logs the three numbers per ref, which mean nothing outside the request.

App Attest

Used only when App Attest is on for your app, as the install response’s attestation.mode says.
  • A challenge works once, for the install it was made for, for five minutes. Pool keeps only its hash.
  • The attestation is checked against Apple’s App Attestation root, the challenge, the key ID and <team ID>.<bundle ID>. A live key accepts only production keys. Anything else is a 400 with code attestation_invalid.
  • Then every cloud assist request carries X-Pool-Attest-Key: <key ID> and X-Pool-Assertion: <base64 assertion>, signed over SHA-256 of the exact body bytes. Each assertion’s counter is accepted once.
  • Under Enforce, a request without a valid assertion gets 401 with attestation_required, or attestation_key_unknown when the key is not on file. PoolKit attests again once and retries.

Run reports

Answers 202 { "status": "recorded" }. Any field beyond these is a 400. Kept 90 days.

Status codes

Error bodies look like { "error": { "code": "quota_exceeded", "message": "…" } } and never repeat what was sent.