When to use this endpoint

The public signature-pad page posts this after drawing. Keep pid, md5 and object type from the received signing link; do not substitute IDs or treat it as a general authenticated form editor.

Authentication and permissions

Public bearer-token route, exempt from CRM-session CSRF. No logged-in user, API key or prior visit to the view page is required; a pending token within the supplied tenant is sufficient.

The handler routes queries explicitly using pid. It does not bind obj_type to the request’s stored type or validate recipient identity.

Parameters

ParameterTypeRequiredDescription
pidInteger stringYesPositive tenant ID from the request link.
md5StringYesExactly 32 lowercase hexadecimal characters identifying an unexpired pending request of the selected document type.
vStringYesJSON-encoded nonempty stroke list, e.g. [{"lx":1,"ly":1,"mx":10,"my":10}]. Every stroke needs finite numeric lx, ly, mx and my coordinates, and at least one segment must move. Stored unchanged after validation.
obj_typeInteger stringNoDefault 0 saves a job; 3 saves a quote. Must match the stored token type (Job=0, Quote=1 internally); other public document types are rejected.

Example request

$result = FM_api('Job_signatureCustomerSave', [
	'pid' => '123',
	'md5' => '0123456789abcdef0123456789abcdef',
	'v' => json_encode([['lx'=>1, 'ly'=>1, 'mx'=>10, 'my'=>10]]),
]);

Example response

{"ok":1}

Errors and unusual responses

ResponseCondition
{"error":"missing or invalid parameter: v"}v absent, blank, malformed, empty or without any drawn segment.
{"error":"pid not valid - internal error"}Tenant ID nonpositive.
{"error":"signature request not found, or expired, or has been signed already"}No matching unexpired pending token of the selected document type; consumed tokens cannot be reused.
{"error":"form does not exist"}Target job/quote is missing/deleted, or its current form is missing.
{"error":"field is not a signature"}A matching named field exists but is not signature type.
{"error":"field does not exist"}No matching named signature field.
{"error":"Unable to save job delivery changes"}A checked database write, audit or transaction failed; local transactional writes roll back. Cross-tenant files/commits are not distributed-atomic.
{"error":"missing or invalid parameter: obj_type"}Public document type is not 0 (Job) or 3 (Quote). A supported but token-mismatched type returns the unavailable-request response instead.

Legacy application errors may be returned with HTTP 200. Check the decoded response for error, not only the HTTP status.

Behaviour and edge cases

  • Job mode checks an active job, resolves the current form and exact sig_field name, and stores v in form_values[name]. Existing other answers are preserved; malformed stored answers become an empty array first.
  • Quote mode requires an active quote, resolves the named signature field’s stable meta.id and writes form_fields[id]. Public obj_type=3 must match the token’s stored Quote request type.
  • Sets object meta.signed_by_request to Unix seconds. Request completion metadata records formatted time, epoch time_e and remote IP; status becomes 1, so an ordinary subsequent call is rejected.
  • If quote-set-won-when-customer-signs is enabled, quote statuses -1,0,4,5,6 change to Won (1); won_date is populated if null. With features2.workflow enabled it records the transition transactionally with the status write, and new-CRM tenants receive the status notification.
  • If request metadata has nonzero send_report (or legacy send_quote), emails the signed document to the original recipient after commit. Also notifies the requesting user when user_id is positive. Unconfirmed follow-ups retain ok and add saved=1, warning and warnings; check mail history before retrying.
  • Checks expiry, document binding and nonblank stroke structure before saving. Locks the pending request and active target; signature, optional Quote Won/Workflow transition and token consumption commit together. No paging applies.

Side effects

  • Writes job answers/meta/last_edited/edited_uuid=Job_signatureCustomerSave with job-cache invalidation, or quote form_fields/meta/last_edited.
  • Marks the request consumed with time/IP metadata; may change quote status and enqueue Workflow work.
  • Attempts requesting-user notification and optional signed-document mail; does not mark the job complete or use Job_emailReport’s sent-marker path.

See it in Fieldmotion

CRM1

Follow a signature-request email, draw and Save. application-sign.js posts the compatibility route Appointment_signatureCustomerSave with pid, md5, obj_type and JSON strokes; it checks a minimum length in the browser only.

CRM2

Uses the same public page/script after the signature-request email. No separate CRM2 save route is used.

Related endpoints