--- title: "Scoping memory to customers, companies and deals" description: "Where a customer, a company or a deal lives, with the requests that put it there." canonical: https://past.dev/docs/memory-api/access-control last-updated: 2026-09-15 --- # Scoping memory to customers, companies and deals > Where a customer, a company or a deal lives, with the requests that put it there. Product: past.dev Memory API. Source: https://past.dev/docs/memory-api/access-control Two rules hold in every pattern on this page. The audience is the scope: a data point names the audience that can read it. The identity is the reader: a recall names the identity it answers as, and reaches that identity's audiences. ### Projects or audiences | Concern | Projects / Audiences | | --- | --- | | Isolation | Projects: nothing crosses between projects, and a code error in one integration cannot reach another project. Audiences: one body of memory, filtered per identity on every read. | | A leaked key | Projects: a project key reaches one project. Audiences: a project key reaches every audience of the project. | | Memory across customers | Projects: never connected. Audiences: the memory of one customer stays inside its audience, and a project-visible data point is read by every identity. | | Caps and usage | Projects: each project carries its own monthly caps and its own usage line in the console. Audiences: one set of caps and one usage line for all customers. | | Operations | Projects: one project and one key per customer, created with the management key. Audiences: one key, one audience per customer, and an identity per reader. | Use separate projects for separate authorization domains, and for separate environments such as staging and production. Use audiences for readers inside one body of memory. Nothing moves between projects: to give a customer its own project later, send its data points again with the new project's key. The number of projects is set by the plan, listed on the [pricing page](/pricing). Credits are counted for the organization across its projects, and each project can carry its own caps. ### One project per customer 1. Create the project with the management key. 2. Mint a project key for it and store the key with the customer's configuration. 3. Send the customer's data points with that key. Recall with the same key, as the customer's user. ```curl,managementkey curl -X POST https://api.past.dev/api/v1/projects \ -H "Authorization: Bearer $PAST_MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme" }' curl -X POST https://api.past.dev/api/v1/projects/acme/keys \ -H "Authorization: Bearer $PAST_MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme production" }' ``` The second response carries `key`, the clear value of the new project key. The API returns it in this response only; the console can reveal it again. The project's slug, `acme` here, is derived from its name and never changes. Every call below takes the project key of the customer's project. ### One project, one audience per customer Create a `fixed` audience per customer that lists the customer's users. Send every data point of that customer with the audience, on every send. Recall as one of the listed users. ```curl,projectkey curl -X PUT https://api.past.dev/api/v1/audiences/acme \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "kind": "fixed", "name": "Acme", "identities": ["sam@acme.example", "ada@acme.example"] }' curl -X POST https://api.past.dev/api/v1/ingest \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "support-2026-04-02-ada", "content": "Ada asked whether the export runs on projects over 50,000 rows. Sam confirmed the fix ships on April 9.", "label": "Support conversation", "timestamp": "2026-04-02T09:15:00Z", "audience": "acme" }' curl -X POST https://api.past.dev/api/v1/recall \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "When does the export fix ship?", "identity": "ada@acme.example" }' ``` A user of another customer is absent from the `acme` list, so a recall as that user returns project-visible memory only. ### CRM memory by company and deal Identities are the users of your application. A trait `company` on each user names the company the user works for. A company is a `rule` audience on that trait, so a new user with the trait joins it with no change to the audience. A user works on several deals and a trait holds one string, so a deal is a `fixed` audience that lists the users on the deal. A data point about the company names the company audience. A data point about one deal names the deal audience. A recall as a user reaches both. ```curl,projectkey curl -X PUT https://api.past.dev/api/v1/identities/dana@example.com \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "traits": { "company": "acme", "team": "sales" } }' curl -X PUT https://api.past.dev/api/v1/audiences/acme \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "kind": "rule", "name": "Acme", "rule": { "match": "all", "conditions": [ { "trait": "company", "operator": "is", "values": ["acme"] } ] } }' curl -X PUT https://api.past.dev/api/v1/audiences/deal-4410 \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "kind": "fixed", "name": "Acme renewal 2026", "identities": ["dana@example.com", "lee@example.com"] }' curl -X POST https://api.past.dev/api/v1/ingest \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "crm-note-8841", "content": "Renewal call with Acme. Sam asked for per-seat billing and a quote for 40 seats before month end.", "label": "Renewal call", "timestamp": "2026-04-03T14:00:00Z", "audience": "deal-4410" }' curl -X POST https://api.past.dev/api/v1/ingest \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "crm-company-acme-2026-04-07", "content": "Acme moved its headquarters to Lyon. Ada is the new procurement contact.", "label": "Company update", "timestamp": "2026-04-07T10:00:00Z", "audience": "acme" }' curl -X POST https://api.past.dev/api/v1/recall \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "Who is the procurement contact at Acme and what did they ask for?", "identity": "dana@example.com" }' ``` ### Read one scope Recall has no filter on content or metadata: the query text, the reader and the time window decide the page. A read limited to one deal runs as a reader identity whose only audience is that deal. Create the reader, list it in the deal's audience, and send the deal's data points with that audience. The read then returns the deal's memory and the project-visible memory, so keep every scope's data points scoped, and put in the project-visible set only what every reader may see. ```curl,projectkey curl -X PUT https://api.past.dev/api/v1/audiences/deal-4410 \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "kind": "fixed", "name": "Acme renewal 2026", "identities": ["dana@example.com", "lee@example.com", "deal-4410-reader"] }' curl -X POST https://api.past.dev/api/v1/recall \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "What did Acme ask for in the renewal?", "identity": "deal-4410-reader" }' ``` ### A lead who changes company A lead is an identity when the lead reads memory, and a subject in the text when your users read about the lead. In both cases the id stays the same when the lead moves. Replace the `company` trait with `PATCH /api/v1/identities/{identity}`. The identity leaves the rule audience of the old company and enters the rule audience of the new one after the window. Earlier data points keep the audience they were sent with, so the history of the old company stays with the old company. ```curl,projectkey curl -X PATCH https://api.past.dev/api/v1/identities/person-2210 \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "traits": { "company": "globex" } }' ``` ### Call transcripts with attendees Send one data point per call, with `timestamp` at the start of the call. Put a header block at the top of the text: the title, the date and the attendees. Then the transcript, one line per speaker turn, with the speaker's name at the start of the line. Name the audience that can read the call: a `fixed` audience of the attendees' identities, or a `rule` audience on a team trait when the whole team reads every call. Recall as any attendee. A call longer than 16,000 characters is split into parts, as [Sending data](/docs/memory-api/sending-data) describes. ```curl,projectkey curl -X POST https://api.past.dev/api/v1/ingest \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "call-9107", "content": "Call: Acme renewal review\nDate: 2026-05-12 14:00 UTC\nAttendees: Dana (Tamtam), Sam (Acme), Ada (Acme)\n\nDana: Let us start with the seat count.\nSam: We are at 38 seats today and expect 45 by June.\nAda: Finance wants one annual invoice.\nDana: Noted. I will send the quote for 45 seats by Friday.", "label": "Acme renewal review", "timestamp": "2026-05-12T14:00:00Z", "audience": "acme-account-team", "identity": "dana@example.com" }' ``` ### A fact that changes Two ways exist to change a fact. A send with the same `id` and new content replaces the data point: the old text and the memory derived from it are gone. A send with a new `id` adds a dated fact, and a recall returns both data points, each with its own date. Use the same id to correct a record. Use a new id for a new event. ```curl,projectkey # A correction: the same id replaces the record. curl -X POST https://api.past.dev/api/v1/ingest \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "crm-note-8841", "content": "Renewal call with Acme. Sam asked for per-seat billing and a quote for 45 seats before month end.", "label": "Renewal call", "timestamp": "2026-04-03T14:00:00Z", "audience": "deal-4410" }' # A new event: a new id adds a dated fact next to the earlier one. curl -X POST https://api.past.dev/api/v1/ingest \ -H "Authorization: Bearer $PAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "id": "email-4f1c9a", "content": "Sam confirmed 45 seats and asked to move the renewal date to October 1.", "label": "Email from Sam", "timestamp": "2026-04-10T08:30:00Z", "audience": "deal-4410" }' ``` ### Four rules - Send `audience` on the data point and `identity` on the read. The audience is the scope. The identity is the reader. - Use a reader identity for a scoped read. Metadata never filters a recall. - Create the audience before a data point names it. An unknown slug is refused with `400 audience-unknown`. - Send `audience` on every re-send of a scoped data point. A re-send without it makes the data point project-visible.