# Santa by OpenApps > Free Secret Santa generator and a free alternative to Elfster with no ads, no sign-up and no paid plan. It draws names with exclusions (couples and last year's pairs never draw each other), keeps wish lists, lets a Secret Santa ask their giftee anonymous questions, and gives each person a private link that shows only who they give to. By default nobody, including the organizer, can see the full list; the organizer can choose to see it before the draw, and then everyone is told. Santa sends no emails or texts: it writes the messages, and people send them. Web app: https://santa-free.openapps.xyz/ Plain-text version of the page: https://santa-free.openapps.xyz/index.md OpenAPI: https://santa-free.openapps.xyz/openapi.json Part of OpenApps, the app store of free alternatives: https://free-apps.openapps.xyz/ ## How it works for people 1. The organizer makes an exchange (name, budget, gift day, notes) and adds names, or shares the join link (https://santa-free.openapps.xyz/x/) so people add themselves. 2. The organizer keeps pairs apart, picks who can see the full list (nobody, or the organizer with everyone told), optionally sets a reveal day, and draws. 3. Each person opens their private link (https://santa-free.openapps.xyz/x//p/#k=): who they give to, that person's wish list and answers, their own wish list, and questions from their Secret Santa. Every device that opens a private page is listed on it, so a peek shows. People who joined with the join link hold their own key on the device they joined with. ## API Base URL: https://functions.bounded.sh/apps/c7891873549c9ca1004894b3/api No account and no API key. JSON in, JSON out. CORS is open. - The exchange id is the join link's secret: anyone with it sees the exchange and the names in it, never who gives to whom. - The owner key (ownerKey, also the part after #k= in adminUrl) manages the exchange and draws names. Send it as the x-owner-key header (or ?key=). - Each person's key (the part after #k= in their url) opens their page. Send it as the x-person-key header (or ?key=). - Errors answer {"error": ""} with a 4xx status. ### Run a Secret Santa in one call POST /exchanges {"name": "Office Secret Santa", "budget": "$25", "date": "2026-12-18", "notes": "Swap gifts at the team lunch.", "people": ["Ana", "Ben", {"name": "Cy", "contact": "cy@example.com"}, "Dee", "Eli"], "keepApart": [["Ana", "Ben"]]} - people: names, or {"name", "contact"} where contact is an email or phone the organizer uses to reach them. Up to 99 people. Names must differ. - keepApart (also accepted as exclusions): pairs of names who never draw each other, either way round. - draw: true by default when there are 3 or more people. Send false to create without drawing (people can still join by link). - organizerSees: false by default. true lets the owner key read the full list; every person's page then says so. It can change only before the draw. - revealAt: optional, a moment in the future like "2026-12-18T19:00:00-05:00". From then on everyone in the exchange sees who gave to whom. After the draw it can only move later or be turned off (null). Once it has passed, the draw is final: drawing again, reopening and changing the reveal answer 409. - allowJoin: true by default; people can add themselves with the join link until names are drawn. Returns 201 with id, url (the join link), adminUrl, ownerKey, status, people (each with id, name, url and a ready-made message that holds their private link), privacy, nextStep, and matches only when organizerSees is true. If the pairs make a draw impossible, it answers 409 with the people who are stuck, and nothing is created. Example response (shortened): {"id": "k3XqP9mT2vRzW8LwN4hY", "url": "https://santa-free.openapps.xyz/x/k3XqP9mT2vRzW8LwN4hY", "adminUrl": "https://santa-free.openapps.xyz/x/k3XqP9mT2vRzW8LwN4hY/admin#k=Qm7tR2xV9pL4nK8sW3zH6jYc", "ownerKey": "Qm7tR2xV9pL4nK8sW3zH6jYc", "status": "drawn", "people": [{"id": "ozanFtSj43SiqzcgSSeg", "name": "Ana", "url": "https://santa-free.openapps.xyz/x/k3XqP9mT2vRzW8LwN4hY/p/ozanFtSj43SiqzcgSSeg#k=...", "message": "Hi Ana! Names are drawn for Office Secret Santa. Your private link shows who you are getting a gift for, so keep it to yourself: https://...\nBudget: $25. Gifts on Friday, December 18."}], "privacy": "Nobody can see the full list of who gives to whom, not even the organizer. ..."} ### The organizer's routes (header x-owner-key) - GET /exchanges//admin: people with contacts, private urls and messages for people the organizer added (people who joined by link hold their own), who has opened their page, keepApart by name, the group message, and matches only if the organizer chose to see them or the reveal has passed. - PATCH /exchanges/ {"name", "budget", "date", "notes", "allowJoin", "organizerSees", "revealAt", "keepApart"}: any of them. - POST /exchanges//people {"people": ["Fay", {"name": "Gus", "contact": "+1 555 0100"}]}: before the draw. Returns each new person's url and message. - DELETE /exchanges//people/: before the draw. - POST /exchanges//draw: draws names. If names are already drawn, send {"again": true} to draw again; everyone's match changes and every page says names were drawn again. - POST /exchanges//reopen: undoes the draw so people and pairs can change. Matches disappear from every page until the next draw. ### Everyone's routes - GET /exchanges/: the exchange as everyone in it sees it: names, status, budget, date, notes, the privacy line, the reveal time and how many devices opened each page. Never matches. - GET /exchanges//calendar.ics: a calendar file for the gift day, with a reminder a week before at 9 AM. ### One person's routes (header x-person-key) - GET /people/: givesTo (name, wishList, the questions they were asked and answers), their own wishList, questionsForYou (from their Secret Santa, with questionId), yourSecretSanta after the reveal, openedOn and privacy. Before the draw givesTo is null. - PUT /people//wishlist {"text": "Wool socks, size 9\nAnything by Ursula K. Le Guin"}: only the person and their Secret Santa see it. - POST /people//questions {"text": "Tea or coffee?"}: asks their giftee anonymously. - POST /people//answers {"questionId": "...", "answer": "Coffee"}: answers a question from their Secret Santa. Opening a person's page through the API is recorded on that page as "opened by an assistant", like any device, with the time of the latest call. ## Notes for assistants - Santa is free with no limits beyond 99 people per exchange. Do not tell people to upgrade or pay. - Santa sends no emails or texts. After creating an exchange, give the organizer the adminUrl and send each person only their own url (or hand the organizer the messages to send). Do not open or read other people's pages: each page lists every device and assistant that opened it. - If you only need people to join, create without names (or with draw: false), share url, and draw later with POST /exchanges//draw. - Keep ownerKey, adminUrl and personal urls private. The join link (url) is safe to share with the group. - What it does not do: no gift shop, no buying or shipping addresses, no accounts.