Skip to main content

Field Placement (beta)

These endpoints give you a programmatic way to position e-signature fields on a Loyva template without using the in-app builder UI. Use them when your system already knows where signatures, dates, or text fields belong — for example, when you generate the source PDF yourself and want signing fields placed at deterministic locations.

Beta

This API surface is in proof-of-concept stage. The request shape may change based on partner feedback. Email [email protected] if you depend on it so we can notify you of any breaking changes before they ship.

Two endpoints, picked by starting point

If you have…UseResult
A fresh PDF and want to create a template from it.POST /partner/templates (multipart)Creates a new Loyva template + DocuSeal counterpart with the PDF and fields baked in. Returns a new template_id.
An existing Loyva template and want to add fields to it.POST /partner/templates/:template_id/fieldsPlaces fields on the existing template. Returns the resolved areas.

Both endpoints share the same field/placement schema, so payloads are portable between them.

Three placement modes (per field)

ModeWhen to useHow
AbsoluteYou already know the (x, y, w, h, page) of each field.placement.mode = "absolute"
AnchorYou want to say "put the signature near the text 'Signed by:'". You don't know the coords, but the source PDF contains a stable text marker.placement.mode = "anchor" — we resolve the text against the PDF's text layer and convert to absolute coords.
Embedded {{ }} tagsYou generate the source PDF and can bake markers directly into it.No placement block — bake the marker into the PDF before uploading. DocuSeal auto-extracts at upload. See Embedded tag syntax.

Modes can be mixed within a single request.

Coordinate system

  • All x, y, w, h, offset_x, offset_y values are normalized 0.0–1.0 fractions of the page (top-left origin, y grows downward).
  • page is 1-based at the API boundary (page 1 = first page).
  • Example: a 200pt-wide field centered on an 8.5"x11" page (612pt wide) has w ≈ 0.327.

If you send values greater than 1 we reject the request — that almost always means you sent pixels or percentages by mistake.


Create a template from a PDF

POST /partner/templates

Required scope: envelopes:write Content-Type: multipart/form-data

Uploads a fresh PDF and (optionally) bakes field placement into the same call. Use this when you don't have a Loyva template yet — drop a PDF, define fields, and you're done in one round-trip. The response returns a new template_id you can use on subsequent envelope and field-placement calls.

Form fields

FieldTypeRequiredDescription
filefile (binary)YesPDF, max 50 MB.
namestringYesDisplay name for the template.
external_idstringNoYour system's reference ID for the template.
fields_jsonstringNoJSON-encoded fields array (same schema as the placement endpoint below). Omit to create an empty template — then call POST /partner/templates/:id/fields to add fields later.

fields_json is a stringified version of the same array you'd send to the placement endpoint. Anchor-mode fields are resolved against the uploaded PDF before being forwarded.

Example (curl)

curl -X POST https://api.stg.loyva.net/api/v2/partner/templates \
-H "X-API-Key: lk_..." \
-F "file=@./loan-agreement.pdf" \
-F "name=Loan Agreement v3" \
-F 'fields_json=[{
"name": "Borrower signature",
"type": "signature",
"role": "Signer 1",
"required": true,
"placement": {
"mode": "anchor",
"anchor_text": "Signed by:",
"offset_y": 0.02,
"w": 0.30,
"h": 0.05
}
}]'

Response (200)

{
"data": {
"template_id": "tmpl_a1b2c3d4e5f6g7h8",
"docuseal_template_id": 5821,
"name": "Loan Agreement v3",
"fields_added": 1,
"fields": [
{
"name": "Borrower signature",
"type": "signature",
"role": "Signer 1",
"required": true,
"anchor_match": { "page": 1, "x": 0.20, "y": 0.83, "w": 0.18, "h": 0.02 },
"areas": [{ "page": 1, "x": 0.20, "y": 0.85, "w": 0.30, "h": 0.05 }]
}
]
}
}

Hold on to template_id — that's the Loyva ID you'll pass to envelope-creation and follow-up field-placement calls.

Error responses

CodeWhen
400Missing file/name form field, or fields_json is not valid JSON.
403Missing envelopes:write scope.
413File too large (50 MB cap).
415File is not application/pdf.
422Validation failed, or an anchor text wasn't found in the uploaded PDF.
500Failed to persist the Loyva template row.
502Signing provider rejected the create.
503Signing provider not configured.

Place fields on an existing template

POST /partner/templates/:template_id/fields

Required scope: envelopes:write

Use this when you already have a template_id — either from an earlier POST /partner/templates call, an existing envelope, or one provisioned for you by Loyva support.

Request body

{
"fields": [
{
"name": "Borrower signature",
"type": "signature",
"role": "Signer 1",
"required": true,
"placement": {
"mode": "absolute",
"areas": [
{ "page": 1, "x": 0.10, "y": 0.85, "w": 0.30, "h": 0.05 }
]
}
},
{
"name": "Borrower date",
"type": "date",
"role": "Signer 1",
"required": true,
"placement": {
"mode": "anchor",
"anchor_text": "Date signed:",
"offset_x": 0.10,
"offset_y": 0,
"w": 0.15,
"h": 0.03
}
}
]
}

Field fields

FieldTypeRequiredDescription
namestringYesDisplay name shown to signers.
typeenumYesOne of signature, initials, text, date, checkbox.
rolestringYesSubmitter role this field belongs to (e.g. "Signer 1", "Client"). Must match a role you use when creating submissions from this template.
requiredboolNoDefaults to false.
default_valuestringNoPrefill for text/date fields.
placementobjectYesOne of the two shapes below.

Placement: absolute

{
"mode": "absolute",
"areas": [
{ "page": 1, "x": 0.10, "y": 0.85, "w": 0.30, "h": 0.05 }
]
}

Repeat objects in areas to place the same field on multiple pages (e.g. an "Initials" field on every page).

Placement: anchor

{
"mode": "anchor",
"anchor_text": "Signed by:",
"occurrence": 1,
"page": 2,
"offset_x": 0,
"offset_y": 0.02,
"w": 0.30,
"h": 0.05
}
FieldTypeRequiredDescription
anchor_textstringYesLiteral text to search for in the PDF text layer. Matching is case-insensitive and whitespace-normalized.
occurrenceintNo1 (default) = first match in document order; 2 = second; etc. Out-of-range → 422.
pageintNoRestrict the anchor search to a specific 1-based page. Omit to search every page.
offset_xfloatNoHorizontal offset from the anchor's top-left, as a 0–1 fraction of page width. Defaults to 0.
offset_yfloatNoVertical offset from the anchor's top-left, as a 0–1 fraction of page height. Defaults to 0.
wfloatYesField width (0–1 fraction of page width).
hfloatYesField height (0–1 fraction of page height).

The anchor must appear in the PDF's text layer. Scanned-image PDFs without OCR'd text will return 422 Anchor text not found.

Response (200)

{
"data": {
"template_id": "tmpl_abc123",
"fields_added": 2,
"fields": [
{
"name": "Borrower signature",
"type": "signature",
"role": "Signer 1",
"required": true,
"areas": [
{ "page": 1, "x": 0.10, "y": 0.85, "w": 0.30, "h": 0.05 }
]
},
{
"name": "Borrower date",
"type": "date",
"role": "Signer 1",
"required": true,
"anchor_match": { "page": 1, "x": 0.20, "y": 0.83, "w": 0.18, "h": 0.02 },
"areas": [
{ "page": 1, "x": 0.30, "y": 0.83, "w": 0.15, "h": 0.03 }
]
}
]
}
}

For anchor-mode fields the response includes anchor_match — the rect of the text we matched — so you can verify the resolution was correct.

Error responses

CodeWhen
403Missing envelopes:write scope.
404Template not found or not owned by your org.
409Template has no document attached / no signing-provider counterpart.
422Validation failed, or an anchor text wasn't found / requested occurrence exceeds matches.
502Could not fetch the template PDF, or signing provider rejected the write.
503Signing provider not configured.

Embedded tags

If you generate the source PDF yourself, the simplest way to position fields is to bake tag markers directly into the document. Loyva's signing provider auto-extracts them at upload time — no POST /fields call needed.

Tag syntax (place anywhere in the PDF text):

{{Borrower Signature;type=signature;role=Signer 1;required=true;width=300;height=60}}
{{Date Signed;type=date;role=Signer 1;required=true;width=150;height=25}}
{{Borrower Initials;type=initials;role=Signer 1;width=80;height=30}}

Attribute reference:

AttributeNotes
typesignature, initials, text, date, number, checkbox, select, radio.
roleSubmitter role (must match what you use when creating submissions).
requiredtrue / false.
width, heightPixels at 72 DPI (this is the only place pixel units appear — everywhere else in this doc uses 0–1 normalized fractions).
defaultOptional prefill value.
readonlytrue to lock the field.

The tag is stripped from the rendered PDF at upload, leaving a field where it sat. Multiple identical tags (same name) place multiple fields.

To upload a tagged PDF as a partner, send it to POST /partner/templates without a fields_json — DocuSeal extracts the tags from the PDF on upload, and the template arrives in Loyva with the fields already in place.


Coordinate cheat sheet

For an 8.5" × 11" US Letter page (612 × 792 pt):

Pixels (72 DPI)Normalized xNormalized y
50pt from left0.082
1" from left0.118
Page center x0.500
50pt from top0.063
1" from top0.091
Bottom 15%~0.85

A standard signature box is typically w: 0.30, h: 0.05 (≈ 180pt × 40pt) — wide enough for a long name without overlapping nearby text.