Docs

Let your users fill a form in your app

Send a user of your system to a prefilled Tepez form, bring them back when they submit, and read what they submitted and its PDF.

This guide connects a Tepez form to a process in your own system, which we call your app. Your app creates an entry for the user, sends them to fill it in, brings them back when they submit, and reads the data and the PDF. The same flow works whether the user reaches the form by a redirect, by an email, or inside your page.

The flow

Your app                          Tepez                              The user
   |                                |                                   |
   | 1. POST /entry/save ---------> |                                   |
   | <-- entry.id, resumeUrlBewit   |                                   |
   |                                |                                   |
   | 2. send the user to resumeUrlBewit ------------------------------> |
   |                                | <------------- fills in, submits  |
   |                                | runs the after-submit rules:      |
   |                                | PDF, emails                       |
   |                                |                                   |
   | <------- 3. redirect to your callback URL, ?entryId=<entryId> ---- |
   |                                |                                   |
   | 4. GET /entry/{entryId} -----> |                                   |
   | <-- status, data, PDF link     |                                   |
  1. Your app creates an entry for the user and stores its id.
  2. Your app sends the user to the entry's link.
  3. After the user submits, Tepez redirects them to a page in your app.
  4. Your app reads the entry from the API: its status, its data and its PDF.

Your app does steps 1 and 4 from its server, with an API key. Step 3 is a rule on the form.

1. Create the entry

Create a draft entry with POST /entry/save, with the values your app already has. Prefill a form shows the request and its full response. Store two values from it next to the user in your app:

  • entry.id: how your app reads the entry later.
  • entry.resumeUrlBewit: the user's personal link to the entry.
curl -X POST https://api.tepez.co.il/v1.0/entry/save \
  -H "x-api-key: $TEPEZ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"form": "<formId>", "data": {"fullName": "Dana Levi", "email": "dana@example.com"}}'
{
  "entry": {
    "id": "<entryId>",
    "status": "saved",
    "data": { "fullName": "Dana Levi", "email": "dana@example.com" },
    "resumeUrlBewit": "https://app.tepez.co.il/e/<entryId>/?b=<bewit>"
  },
  "entryId": "<entryId>"
}

When the user comes back to this step before submitting, for example after closing the tab, send them to the same entry rather than creating another. Their draft is still there.

2. Send the user to the form

Redirect the user's browser to resumeUrlBewit, send it to them by email or text message, or open it in an iframe on your page (see Embed a form). Use the link exactly as the API returned it. The link needs no sign-in: it works until the entry is submitted, and for at most 2 years.

3. Bring the user back after they submit

By default, after the user submits, the form shows a thank-you message. To bring them back to your app, the form redirects them to a URL instead. The redirect is a rule on the form, one of its after-submit rules. The Tepez team usually sets it up for you: tell us the URL to redirect to.

The URL can be the same for everyone, or built from the entry:

  • Static: https://your-app.example.com/tepez/done.
  • With the entry id: https://your-app.example.com/tepez/done?entryId={{ data.entry.id }}. Tepez replaces {{ data.entry.id }} with the submitted entry's id, so the page knows which entry to check.
  • Chosen by your app per entry: add a hidden text field to the form, such as redirectUrl, and set the redirect URL to {{ model.redirectUrl }}. Your app puts the URL in that field when it creates the entry, so each process can return the user to its own page.

GET /form/{formId} shows the rule under postSubmit.ui:

"postSubmit": {
  "ui": [
    {
      "type": "redirect",
      "redirectOptions": { "url": "https://your-app.example.com/tepez/done?entryId={{ data.entry.id }}" }
    }
  ]
}

A user who submits entry <entryId> lands on https://your-app.example.com/tepez/done?entryId=<entryId>.

  • The redirect happens after Tepez has saved the entry, archived its PDF and sent its emails. By the time the user reaches your page, everything in step 4 is ready.
  • The URL must start with https:// or http:// once the values are filled in. If it doesn't, for example because redirectUrl is empty, Tepez skips the redirect and shows the thank-you message instead.
  • Don't trust the callback on its own. Anyone can open your callback URL with any entryId, and a user who closes the tab right after submitting never reaches it. Treat the callback as a signal to check the entry, and check it again whenever the user returns to your app.

4. Read the entry

Read the entry with GET /entry/{entryId}, using the id your app stored in step 1, not an id taken from the callback URL alone.

curl https://api.tepez.co.il/v1.0/entry/<entryId> \
  -H "x-api-key: $TEPEZ_API_KEY"

A submitted entry, trimmed:

{
  "id": "<entryId>",
  "form": "<formId>",
  "status": "submitted",
  "idx": 1,
  "submitIdx": 1,
  "data": {
    "fullName": "Dana Levi",
    "email": "dana@example.com",
    "address": { "city": "Haifa", "street": "Herzl 10" },
    "phone": "050-1234567"
  },
  "actions": [
    { "id": "<actionId>", "type": "save", "time": "2026-09-30T16:43:48.664Z", "ip": "<ip>", "userAgent": "curl/8.16.0", "user": "<userId>" },
    { "id": "<actionId2>", "type": "resume", "time": "2026-09-30T16:47:11.372Z", "ip": "<ip>", "userAgent": "Mozilla/5.0 …" },
    { "id": "<submitActionId>", "type": "submit", "time": "2026-09-30T16:47:23.514Z", "ip": "<ip>", "userAgent": "Mozilla/5.0 …" }
  ],
  "archivedRenders": [
    {
      "id": "<renderId>",
      "action": "<submitActionId>",
      "type": "template",
      "template": { "type": "auto" },
      "file": {
        "name": "Job application.pdf",
        "size": 18068,
        "type": "application/pdf",
        "s3Key": "<formId>/<entryId>/<renderId>/Job application.pdf",
        "s3Bucket": "<bucket>",
        "url": "https://<bucket>.s3.eu-west-1.amazonaws.com/<formId>/<entryId>/<renderId>/Job%20application.pdf?<presigned-query>"
      }
    }
  ],
  "submitTime": "2026-09-30T16:47:23.514Z",
  "createTime": "2026-09-30T16:43:48.668Z",
  "modifyTime": "2026-09-30T16:47:23.521Z",
  "changedAt": "2026-09-30T16:47:24.193Z"
}

Act on the entry's status:

statusWhat it meansWhat your app does
submittedThe user finished.Store data, and download the PDF from archivedRenders[].file.url if the form archives one. Files and PDFs explains the PDF. The process is done.
savedThe user hasn't submitted yet: they saved a draft, closed the tab, or haven't started.Send the user back to resumeUrlBewit, which the response includes while the entry is saved.

The submitted entry has no resumeUrlBewit: the link stopped working when the user submitted. actions shows the entry's history, including each time the user opened the link (resume).

Let the user revise a submitted entry

To let the user change an entry they already submitted, edit it back to saved with POST /entry/{entryId}/edit and {"status": "saved"}. The response carries a new resumeUrlBewit: send the user there, and repeat steps 3 and 4. See Edit an entry.

To correct a submitted entry yourself, or to delete an entry when the process ends, see Update and delete entries. To submit an entry on the user's behalf, without sending them to the form, see Submit entries from your server.

Troubleshooting

SymptomCause and fix
The user sees the thank-you message instead of returning to your appThe form has no redirect rule, or its URL is empty or isn't an http(s) URL once the values are filled in. Check postSubmit.ui in GET /form/{formId}.
The callback URL arrives with an empty entryIdThe expression in the rule is misspelled, so it evaluates to nothing. Ask us to check the form's redirect rule.
The entry is saved when the user reaches your callbackThe user reached the callback without submitting, for example by going back in the browser. Send them to resumeUrlBewit again.
The link shows You cannot resume editing this form entry because it was already submitted.The entry was submitted. Read it with GET /entry/{entryId}, or edit it back to saved to let the user revise it.
No archivedRenders on the submitted entryThe form doesn't archive a PDF on submit. See Files and PDFs to render one, or ask us to set the form to archive one.
403 You have insufficient permissions to perform the action.The entry belongs to another account. A key reaches only its own account.
404 Could not find an entry with ID …The id is wrong. Check that you stored entry.id, not the form id.

Errors explains the error format and lists more messages.

Every response from the API carries an x-tepez-request-id header. Quote it when you contact us.

Email support with the request id

Question about this page? Email support@tepez.co.il

On this page