For developers

Send call sheets into Callsheet Pro

Your own tools can push a shoot day straight into a Callsheet Pro account. No PDF, no import step: send the data, and the day is on the phone within seconds.

Three ways in. Pick yours.

A PDF on your phone

Tap Share on the PDF and pick Callsheet Pro. Built into the iOS and Android apps. No key, no API.

A call sheet by email

Forward it to your personal address from Settings, Email Forwarding. The attachment is read automatically.

A tool that holds the data

Scheduling software, a production office system, a spreadsheet script, a Shortcut. That is what this page is for.

Get your key in 3 steps

Every Callsheet Pro account can make a key, Free or Pro. You never need to email anyone.

  1. Open Callsheet Pro and go to Settings. On the phone: the gear at the top right. On the web app: Settings in the sidebar.
  2. Scroll to API key and tap Create API key. It sits right under Email Forwarding.
  3. Tap the copy button and paste the key where your tool wants it. The key starts with csp_. For safety it is shown only this once; if you lose it, tap Make a new key.
Settings in Callsheet Pro showing the API key section with a freshly created key and its copy button

The key writes into your own account only. Treat it like a password: anyone holding it can add and change call sheet days in your account, and nothing else.

Try it in one minute

You need a Mac, Linux or Windows terminal with curl (every Mac has it). Put your key in place of csp_YOUR_KEY and run:

curl -X POST "https://us-central1-callsheet-pro.cloudfunctions.net/api/v1/days" \
  -H "Authorization: Bearer csp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "my-first-test",
    "day": {
      "productionTitle": "API test",
      "dateISO": "2026-10-20",
      "generalCallTime": "07:00",
      "locations": [{ "name": "Studio A", "address": "Kleine Weg 1, Amsterdam", "callTime": "07:00" }]
    }
  }'

You get back {"result":"created", ...}. Open Callsheet Pro: there is a production called API test with one day. That is the whole trick.

Now change the call time and send it again:

curl -X POST "https://us-central1-callsheet-pro.cloudfunctions.net/api/v1/days" \
  -H "Authorization: Bearer csp_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalId": "my-first-test",
    "day": {
      "productionTitle": "API test",
      "dateISO": "2026-10-20",
      "generalCallTime": "08:00",
      "locations": [{ "name": "Studio A", "address": "Kleine Weg 1, Amsterdam", "callTime": "08:00" }]
    }
  }'

This time the answer says "result":"updated", and the same day in the app now reads 08:00 instead of a second copy appearing. The externalId is what makes that happen: same id, same day.

Done testing? In Callsheet Pro, open All Days and swipe the day to the left to delete it (or tap Edit list, then the trash icon next to it). On the web app the trash icon sits on each row of All Days; tap it twice.

Got a 401? The key is wrong or was replaced. Make a new one in Settings, API key, and paste it again.

Got a 422? The issues list in the answer names exactly which field to fix.

Build an iOS Shortcut

A Shortcut turns any text on your iPhone into a shoot day: a call sheet pasted into a WhatsApp message, the body of an email, a note. Select the text, tap Share, pick the Shortcut, and the day appears in Callsheet Pro. Each send reads the text with the same parser as a PDF upload and spends one upload from your monthly allowance.

Have the call sheet as a PDF? You do not need a Shortcut: tap Share on the PDF and pick Callsheet Pro.

  1. Open the Shortcuts app and tap the plus at the top right. Tap the name at the top, call it Send to Callsheet Pro.
  2. Add the action Get Contents of URL. Tap Search Actions at the bottom, type the name, tap it. Then tap the blue URL word and paste this:
    • https://us-central1-callsheet-pro.cloudfunctions.net/api/v1/days
  3. Expand the action (tap the small arrow) and fill it in:
    • Method: POST
    • Headers: add Authorization with the value Bearer csp_YOUR_KEY (the word Bearer, a space, then your key), and add Content-Type with the value application/json
    • Request Body: JSON. Tap Add new field, choose Text, type input as the key, then tap the value, tap Select Variable and pick Shortcut Input
  4. Set up the input. Picking Shortcut Input adds a Receive ... from ... step at the top. Tap Continue under If there's no input and choose Get Clipboard, so a copied call sheet works too. To get the Shortcut into the Share menu, tap the i (Details) at the bottom and switch on Show in Share Sheet.
  5. Add the action Show Content (on older iOS it is called Show Result). It shows the answer: created on success, or the message that says what went wrong.
  6. Try it. Copy a call sheet text, tap the play button at the bottom right. The first time, iOS asks whether the Shortcut may send text to us-central1-callsheet-pro.cloudfunctions.net: tap Always Allow. After a few seconds the answer appears, and the day is in Callsheet Pro. From then on: select text in a message or email, tap Share, pick Send to Callsheet Pro.

One send per 15 seconds, and each send spends one upload from your monthly allowance, like scanning a PDF in the app. If the text is not a call sheet at all, the answer says PARSE_FAILED and nothing is added.

Endpoint

POST https://us-central1-callsheet-pro.cloudfunctions.net/api/v1/days
Authorization: Bearer csp_YOUR_KEY
Content-Type: application/json

One call sends one shoot day. The response tells you whether it was created or updated. This is the only route; there is no way to read, list or delete days through the API.

Structured mode (recommended)

Send the day as JSON in a day object. Instant, exact, and free of upload credits.

{
  "externalId": "your-stable-id-for-this-sheet",
  "day": {
    "productionTitle": "Night Shift",
    "dateISO": "2026-07-14",
    "generalCallTime": "07:00",
    "wrapTime": "19:00",
    "locations": [
      { "name": "Studio A", "address": "Kleine Weg 1, Amsterdam",
        "callTime": "07:00", "parking": "Lot B" }
    ],
    "crew": [
      { "role": "Gaffer", "name": "A. Person",
        "phone": "+31600000000", "callTime": "07:00" }
    ],
    "schedule": [
      { "time": "08:00", "description": "First setup", "teams": [] }
    ]
  }
}

Required: productionTitle, and a date (dateISO as YYYY-MM-DD, preferred, or date as free text). Everything else is optional.

Updates (upsert by externalId)

externalId is your tool's own stable id for the sheet (max 128 characters). Re-send the same externalId and the existing day in the app is updated in place instead of duplicated. This is how live changes work: when the sheet changes in your tool, just send it again.

Without externalId, every call creates a new day.

Loose mode

If you cannot produce our JSON, send any text instead and our parser turns it into a structured day. Costs the account owner one upload credit per call (same as scanning a PDF in the app) and is limited to one call per 15 seconds.

{
  "externalId": "your-stable-id-for-this-sheet",
  "input": "CALL SHEET - Night Shift - Tuesday, July 14, 2026\nGeneral call 07:00 ..."
}

Send exactly one of day or input, never both. input is capped at 100,000 characters. The API accepts no files: a PDF has to become text before it is sent, or go through Share in the app.

Field reference (day object)

FieldTypeNotes
productionTitlestringRequired. Days with the same title group into one production in the app.
seriesNamestringOptional series name.
episodeInfostringFor example "S2E05".
dayNumbernumberShoot day number.
dateISOstringYYYY-MM-DD. Preferred date field.
datestringHuman-readable date, fallback when dateISO is absent.
countrystringISO country code of the shoot, used for phone number formatting.
generalCallTimestringFor example "07:00".
wrapTimestringExpected wrap.
weatherstringFree text.
sunrise / sunsetstringFor example "05:42".
warningsstring[]Safety or general warnings shown prominently.
locationsLocation[]See shapes below.
crewCrewMember[]See shapes below.
scheduleScheduleItem[]See shapes below.
scenesScene[]See shapes below.
transportTransportRow[]See shapes below.
castCastMember[]See shapes below.
emergencyobjecthospitalName, hospitalAddress, hospitalPhone, firstAid, counselor.
invoiceEmail and friendsstringinvoiceCompany, invoiceDetails, projectNumber: billing info for crew invoices.
gearAndSettingsobjectgear: string[], settings: [{ label, value }], warning: string, groups: [{ title, gear, settings }]. Send groups when the technical block is printed under two or more subheadings (broadcast/OB sheets: TECHNIEK, AUDIO, EVS, VIDEOSIGNALEN); gear and settings are then derived from it and anything you put in them is ignored. A single group is folded into the flat arrays.

Object shapes:

All string fields accept null or can be omitted; they default to empty.

Responses and errors

{ "result": "created", "dayId": "...", "dayIds": ["..."],
  "externalId": "...", "warnings": [] }

201 for created, 200 for updated. warnings lists non-fatal problems (for example a scene pointing at an unknown location). Fix them when convenient; the day was saved.

Errors produced by the API look like:

{ "error": { "code": "INVALID_DAY", "message": "how to fix it",
  "issues": ["field: problem"], "hint": "https://developer.callsheetpro.app" } }

An HTTP platform or proxy can reject malformed HTTP or malformed application/json before the handler runs; in that case the response may be a plain 400. Check the HTTP status and content type before decoding the JSON error envelope.

HTTPcodeMeaning and fix
400INVALID_JSON / INVALID_BODYMalformed body. Send a JSON object with exactly one of day or input.
401MISSING_AUTH / INVALID_API_KEYKey absent, wrong, or replaced. Make a new one in Callsheet Pro under Settings, API key, and update the tool.
404NOT_FOUNDThe only route is POST /v1/days.
405METHOD_NOT_ALLOWEDSend a POST.
413PAYLOAD_TOO_LARGEBody over 1 MB or input over 100,000 characters. Send one day per request.
422INVALID_DAYDay rejected; the issues array lists exactly what to fix.
422PARSE_FAILEDLoose mode could not produce a usable day. Check the optional issues array, improve the input, or use structured mode.
422RESPONSE_TRUNCATEDThe call sheet was too long to finish parsing in one response. Split it into one day per request; no credit was charged.
422FILE_TOO_LARGEInput too large for the parser. Send less text, or split it per day; no credit was charged.
422PDF_PASSWORD_PROTECTEDThe PDF is password protected. Remove the password first; no credit was charged.
422IMAGE_TOO_LARGEThe image is larger than the parser accepts. Downscale it and retry; no credit was charged.
422PDF_NOT_VALIDNot a readable PDF. Re-export it and retry; no credit was charged.
422PDF_TOO_MANY_PAGESThe PDF has more pages than the parser accepts. Send the call sheet pages only; no credit was charged.
429RATE_LIMITEDToo fast. Send requests one after another and retry after a short wait.
429DAILY_LIMIT_REACHED500 requests today used. Retry after midnight UTC.
429PARSE_LIMIT_REACHEDMonthly upload allowance used (loose mode). Switch to structured mode, which is free, or wait for the monthly reset.
503UPSTREAM_BUSYParser busy (loose mode only). Retry in a minute; no credit was charged.
500INTERNALOur fault. Retry once; if it persists, email support@earlystudios.nl.

Limits

Your key: safety and replacing it

Lost or leaked? In Callsheet Pro, Settings, API key, tap Make a new key. The old key stops working the same second; give the new one to the tools that need it. We store only a hash of your key, so nobody, including us, can read it back: that is why it is shown once.

Deleting your account deletes the key with it.

Prompt for coding tools

Building the integration with a coding tool (Claude Code, Codex, Cursor, or similar)? Paste this prompt and let it work.

Add an "Export to Callsheet Pro" feature to this project.

API: POST https://us-central1-callsheet-pro.cloudfunctions.net/api/v1/days
Auth: header "Authorization: Bearer <key>". The key starts with csp_. For a
single-account server integration, load it from an environment variable (for
example CALLSHEET_PRO_API_KEY). For a multi-user product, collect one key per
Callsheet Pro user and store it encrypted in your backend. Never hardcode,
log, commit, or ship keys in a public frontend bundle. Every Callsheet Pro
user makes their own key in the app: Settings, API key, Create API key.

Body: JSON object { "externalId"?: string, "day": object }.
- externalId: strongly recommended. Use this project's stable id for the
  call sheet (max 128 chars).
  Re-sending the same externalId updates the day in the app instead of
  duplicating it, so exports are safe to repeat after every change.
- day: the call sheet as JSON. Required: productionTitle, and dateISO
  ("YYYY-MM-DD") or date (free text). Optional fields: seriesName,
  episodeInfo, dayNumber, country, generalCallTime, wrapTime, weather,
  sunrise, sunset, warnings (string[]),
  locations [{name, address, callTime, parking, contactName, contactPhone}],
  crew [{role, name, phone, email, callTime, callLocation, team}],
  schedule [{time, endTime, description, teams (string[]), sceneNumber}],
  scenes [{number, description, cast (string[]), scheduledTime, locationName}],
  transport [{kind, label, driver, driverPhone, passengers, time, from, to, ref}],
  cast [{role, name, phone, pickupTime, makeupTime, wardrobeTime, callTime,
  onSetTime, note}], emergency {hospitalName, hospitalAddress, hospitalPhone,
  firstAid, counselor}, invoiceEmail, invoiceCompany, invoiceDetails,
  projectNumber.
  Every scene.locationName should exactly match a locations[].name.
  Always send the FULL day on every export: omitted lists are cleared.

Alternative when structured mapping is not feasible: send
{ "externalId": string, "input": "<the call sheet as plain text>" } instead of
"day". That costs the user 1 upload credit per call and allows one call per
15 seconds, so prefer "day".

Responses: 201 created / 200 updated, body { result, dayId, warnings }.
Surface warnings to the user. API-handler errors are
{ error: { code, message, issues } }; the message says how to fix. Handle:
401 invalid key (tell the user to make a new key in Callsheet Pro under
Settings, API key, and paste it again), 422 INVALID_DAY (fix the listed
issues), 429 (back off and retry sequentially, never parallel), 503 (retry
once after a minute).

If this project has a user interface, use the official "Export to Callsheet
Pro" button for the export action: ready-made HTML snippet and image assets
at https://developer.callsheetpro.app/#button

Verify the integration by sending a minimal day and confirming a 201 created
or 200 updated response. Then tell the user to open the Callsheet Pro app:
the day appears there automatically within seconds, grouped under its
production title.

Full docs: https://developer.callsheetpro.app (plain text:
https://developer.callsheetpro.app/developers.md)

The official button

Put this in your tool's interface on the action that sends a sheet to Callsheet Pro. Use it as-is; do not change the colors or the wording.

Export to Callsheet Pro button, dark Export to Callsheet Pro button, yellow

Downloads: dark SVG / PNG / PNG 2x, yellow SVG / PNG / PNG 2x.

Or render it natively with plain HTML (no image, no font files needed):

<!-- Export to Callsheet Pro button (dark). Attach your export handler. -->
<button type="button" style="display:inline-flex; align-items:center; gap:8px;
  height:44px; padding:0 20px; background:#000; border:1px solid #46484d;
  border-radius:12px; cursor:pointer;
  font-family:Inter, system-ui, -apple-system, 'Segoe UI', sans-serif;">
  <span style="font-size:14px; color:#aaabb0;">Export to</span>
  <span style="font-size:15px; font-weight:800; letter-spacing:-0.02em;
    color:#f6f6fc;">CALLSHEET<span style="color:#facc15;">PRO</span></span>
</button>

<!-- Yellow variant: swap the three style blocks for -->
<!-- button: background:#facc15; border:none;                  -->
<!-- "Export to" span: color:rgba(0,0,0,0.78);                 -->
<!-- wordmark span: color:#000; (and drop the inner PRO span)  -->